【问题标题】:Response code 401 triggering basic authentication before the jquery ajax error handler响应代码 401 在 jquery ajax 错误处理程序之前触发基本身份验证
【发布时间】:2012-02-06 01:38:31
【问题描述】:

我有一个场景,我必须使用“表单身份验证”处理 ajax 请求的身份验证。根据我之前的 stackoverflow 帖子的一些搜索和帮助,我决定使用here 中描述的方法。

这个想法是为未经身份验证的请求发回 401 响应,然后在 AJAX 错误处理程序中处理它。所以我在我的 ASP.net MVC3 布局页面中有一个 AJAX 错误处理程序,当它收到未经身份验证的 ajax 请求的 401 响应时,它会将浏览器重定向到登录页面。这是 ajax 错误处理程序。

$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
    if (jqXHR.status == "401") {
        window.location.replace(loginUrl);
    }
    ....
});

这在我的本地 IIS 7.5 服务器上运行良好。但不幸的是,在托管我的网站的服务器上,在 AJAX 错误处理程序运行并将浏览器重定向到登录页面之前,我会在未经身份验证的 ajax 请求(例如会话超时)上收到基本身份验证弹出窗口。当我通过按取消按钮取消“需要身份验证”弹出窗口时,AJAX 错误处理程序然后运行,我被重定向到登录页面。

那么,为什么浏览器会在运行 AJAX 错误处理程序之前显示身份验证弹出窗口?

编辑:托管服务器正在运行 IIS 6。

【问题讨论】:

  • 小心点击“此处”上方此问题文本中的链接...它报告木马感染。

标签: asp.net-mvc-3 jquery


【解决方案1】:

对我来说这很简单。大多数具有匿名身份验证的 IIS 网站还启用了默认的 Windows 身份验证

关闭 Windows 身份验证,当站点检测到 401 时,即使来自 ajax 调用也会弹出登录屏幕。

<security> <authentication> <anonymousAuthentication enabled="true" /> <windowsAuthentication enabled="false" /> </authentication> </security>

【讨论】:

    【解决方案2】:

    正如Softlion所说的

    这是一个很容易回答的常见问题。 .net授权模块将401转换为登录>页面的302。浏览器永远不会看到 401,只有 302。

    如果您使用的是 .net 4 及更高版本,请使用以下代码

    HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
    

    这对我来说很好。

    【讨论】:

      【解决方案3】:

      解决方案here 是编写一个自定义 HttpModule 来解决 MVC 框架的默认行为。一旦我终于能够注册模块 (cheers David Ebbo),它就对我有用。您可能想选择自己的呼叫标准SuppressAuthenticationRedirect

      public class SuppressFormsAuthenticationRedirectModule : IHttpModule {
        private static readonly object SuppressAuthenticationKey = new Object();
      
        public static void SuppressAuthenticationRedirect(HttpContext context) {
          context.Items[SuppressAuthenticationKey] = true;
        }
      
        public static void SuppressAuthenticationRedirect(HttpContextBase context) {
          context.Items[SuppressAuthenticationKey] = true;
        }
      
        public void Init(HttpApplication context) {
          context.PostReleaseRequestState += OnPostReleaseRequestState;
          context.EndRequest += OnEndRequest;
        }
      
        private void OnPostReleaseRequestState(object source, EventArgs args) {
          var context = (HttpApplication)source;
          var response = context.Response;
          var request = context.Request;
      
          if (response.StatusCode == 401 && request.Headers["X-Requested-With"] == 
            "XMLHttpRequest") {
            SuppressAuthenticationRedirect(context.Context);
          }
        }
      
        private void OnEndRequest(object source, EventArgs args) {
          var context = (HttpApplication)source;
          var response = context.Response;
      
          if (context.Context.Items.Contains(SuppressAuthenticationKey)) {
            response.TrySkipIisCustomErrors = true;
            response.ClearContent();
            response.StatusCode = 401;
            response.RedirectLocation = null;
          }
        }
      
        public void Dispose() {
        }
      
        public static void Register() {
          DynamicModuleUtility.RegisterModule(
            typeof(SuppressFormsAuthenticationRedirectModule));
        }
      }
      

      【讨论】:

        【解决方案4】:

        等等!我以为你说的是​​ Ajax 请求,你怎么能得到一个关于 ajax 请求的弹出窗口?我很确定您甚至在 AJAX 调用之前在其他地方触发了对 URL 的调用。从您的场景证明,当您取消弹出窗口时,您的实际 ajax 请求正在发出,因此您可以进行 ajax 重定向。

        这个想法是为未经身份验证的请求发回 401 响应,然后在 AJAX 错误处理程序中处理它

        只有发送 ajax 请求才能得到 ajax 响应,如果发送正常的 http 请求,则会得到一个弹出窗口。这与 .Net 或 Java 无关 :)

        【讨论】:

        • 我不知道返回 401 响应的 ajax 请求是否应该触发浏览器显示身份验证弹出窗口,但确实会发生。我正在发出一个纯未经身份验证的 ajax 请求并返回 401 响应,这会导致浏览器显示“需要身份验证”弹出窗口。如果我为未经身份验证的 ajax 请求返回一些自定义响应代码(例如 601),则浏览器不会显示“需要身份验证”弹出窗口。然而,ajax 错误处理程序会运行,然后我可以使用它来使用普通请求将浏览器重定向到登录 url。这种方法似乎有效
        • 真正的想法是通过 ajax 发送一个有效的响应代码并在回调处理程序中处理它并重定向:)
        【解决方案5】:

        这是一个很容易回答的常见问题。 .net 授权模块将 401 转换为登录页面的 302。浏览器永远不会看到 401,只有 302。

        当然,这不能很好地与 ajax 调用配合使用。

        我尝试过并且目前正在使用的最佳解决方案是编写一个捕获 401 的新属性并将其转换为由 jquery ajax 处理程序捕获的 ... 409。

        它是付费产品的一部分,所以我不能提供任何代码。

        【讨论】:

        • 我已经处理了将 401 转换为 302 的抑制。但最后我返回了 401,这触发了浏览器中需要身份验证的弹出窗口。今天,我尝试返回一个自定义错误代码,比如 601 而不是 401,然后在 jquery ajax 错误处理程序中处理它。这似乎适用于我的登台服务器,但这种方法会有什么缺陷吗?
        • 是的,改用 409 更安全。 4xx 是身份验证错误(标准化)。 6xx 未标准化。 “4xx 类状态代码适用于客户端似乎出错的情况。”见en.wikipedia.org/wiki/List_of_HTTP_status_codes。我使用 409 是因为我更喜欢使用存在的错误代码,因为某些浏览器可能不支持不存在的 http 返回代码。我的测试表明 409 在 IE、Chrome、FF 和 Safari 浏览器中得到了很好的支持,并且不会触发任何特殊的浏览器功能(302 会)。
        【解决方案6】:

        .net 不会捕获 401 错误。我所做的是将 IIS 错误页面从默认的 401 页面设置为我自己的静态 401 页面。从那个页面我使用 javascript 重定向到另一个处理程序。

        【讨论】:

          【解决方案7】:

          IIS 6 处于集成模式?我不相信有任何这样的事情,除非你在谈论集成身份验证。

          我的猜测是您使用的是非 aspx 扩展,因此在 IIS6 上,这意味着它甚至没有访问 .net 进程。所以,IIS 正在使用它自己的 401 错误响应页面。

          可能的解决方案是强制所有请求由 .net 进程处理。

          您的主机必须进入 IIS 属性 > 配置 > 通配符映射 - 并将所有内容映射到 .net 进程。

          【讨论】:

          • ScottE,抱歉信息不正确,IIS 6 确实没有集成管道模式。无论如何,关于你的猜测,我确实有一个 IHttpModule 实现,但它正在做它应该做的事情,即为未经身份验证的 ajax 请求返回 401 响应。没有其他用于处理请求的非 aspx 扩展,所以我猜该请求正在由 .net 进程处理。您可以在我的问题中提供的链接中找到我正在使用的 IHttpModule 实现。感谢您的回复。
          • 不,在 IIS 6 中,默认情况下 .net 进程不处理无扩展名 url。因此,该请求甚至没有命中您的 httpmodule。如果 .net 处理所有请求,那么你应该没问题。
          • 身份验证适用于非 ajax 请求。我正在使用表单身份验证,如果有未经身份验证的(非 ajax)请求,我会正确重定向到登录页面。登录后,我可以使用访问所有 asp.net MVC 控制器的操作方法。该问题仅发生在未经身份验证的 ajax 请求中,我从我的模块发送 401 响应。不幸的是,IIS 6 添加了两个标头“WWW-Authenticate”,其值为“Negotiate”和“NTLM”,这导致浏览器触发身份验证弹出窗口。
          • 好的,明白了。这确实是一种奇怪的行为!您是否在 web 配置的 httpModules 部分尝试过 ,添加您的 httpmodule,然后添加回相关的 .net 模块?也许文件身份验证模块跳入了错误的位置。我遇到了这个问题,并形成了身份验证和 url 重写。
          【解决方案8】:

          尝试从响应中删除 WWW-Authenticate 标头。

          【讨论】:

          • 我尝试使用 IHttpModule 的“EndRequest”事件处理程序中的 response.Headers.Remove("WWW-Authenticate") 从响应中删除标头“WWW-Authenticate”,但代码抛出[PlatformNotSupportedException:此操作需要 IIS 集成管道模式。]。所以我怀疑我们是否可以从响应中删除标题。
          • 只能在IIS7集成管道模式下使用response.Headers方法,在IIS 6中使用response.ClearHeaders()和response.AppendHeader()方法
          猜你喜欢
          • 2013-08-31
          • 1970-01-01
          • 1970-01-01
          • 2016-10-13
          • 1970-01-01
          • 1970-01-01
          • 2012-06-17
          • 1970-01-01
          • 2018-10-09
          相关资源
          最近更新 更多