【问题标题】:Forms Authentication and POST requests from AJAX来自 AJAX 的表单身份验证和 POST 请求
【发布时间】:2009-12-11 23:02:44
【问题描述】:

我们有一个受表单身份验证保护的 ASP.NET 应用程序。该应用大量使用 MS AJAX 来调用其网络服务。

当表单身份验证超时并且发生 GET 请求时 - 一切正常(用户被重定向到登录页面)。

BUT 当表单身份验证超时并且发生 POST-请求 (ajax) - 不发生重定向,而是应用返回“401 unathorized”并且浏览器提示用于用户名和密码(不是登录表单,而是浏览器内置对话框)。当然,输入任何用户名/密码都无济于事。

我该如何处理?

更新: 在查看 firebug 后,我发现常规 POST 请求重定向到登录很好,只有 Web 服务调用会抛出“401 Unauthorizes”。 常规请求和 Web 服务之间的区别在于 URL。对于常规的后请求,它是“page.aspx”,对于 Web 服务,它是“service.asmx/MethodName”...

【问题讨论】:

  • 您是否查看过 FireBug 实际发送到服务器的内容以及响应的内容?浏览器的内置提示通常意味着您尝试访问的资源受到基本或 NTLM 身份验证的保护。您是否为您网站的某些部分启用了此类身份验证?
  • 是的,在 IIS 设置中,我们启用了“Windows 集成”身份验证(以及“匿名访问”)。谢谢,我会试试 Firebug

标签: asp.net forms-authentication


【解决方案1】:

好的,回答我自己的问题。

在调查此问题并进行更多研究后,我发现当 Web 应用程序受 Forms-Authentication 保护并且用户未通过身份验证时,会发生以下情况:

  • 如果是 GET 请求 - 用户是 重定向到登录页面。
  • 如果是对页面的 POST 请求 - 用户是 重定向到登录页面。
  • 如果是 对网络服务的 POST 请求 - 用户得到 401-unauthorized

这就是 ASP.NET 的工作原理

如果 Web 服务被 AJAX(xmlHttpRequest 对象)调用并返回 401 - 当然浏览器会显示一个弹出登录框。

现在,您应该做的是向 Application_PostAuthenticateRequest 添加一些代码,以防止为 web 服务抛出 401。

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    if (Request.RequestType == "POST" //if its POST
        && !User.Identity.IsAuthenticated //if user NOT authed
        && !HasAnonymousAccess(Context) //if it's not the login page
        )
    {
        //lets get the auth type
        Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
        SystemWebSectionGroup grp = (SystemWebSectionGroup)config.GetSectionGroup("system.web");
        AuthenticationSection auth = grp.Authentication;
        //if it FORMS auth
        if(auth.Mode== AuthenticationMode.Forms)
        {

            //then redirect... this redirect won't work for AJAX cause xmlHttpRequest can't handle redirects, but anyway...
            Response.Redirect(FormsAuthentication.LoginUrl, true);
            Response.End();

        }
    }
}
public static bool HasAnonymousAccess(HttpContext context)
{
    return UrlAuthorizationModule.CheckUrlAccessForPrincipal(
        context.Request.Path,
        new GenericPrincipal(new GenericIdentity(string.Empty), null),
        context.Request.HttpMethod);
}

【讨论】:

  • @jazbit,你能指出一些关于 Web 服务 401 状态代码的文档吗,我有一个场景,我正在检查会话 ecpiry 并正在执行重定向,结果 401 到客户端
  • Response.End 通常是一件坏事。通常你想要response.Redirect(url, False); HttpContext.Current.ApplicationInstance.CompleteRequest();
【解决方案2】:

我看到了两种解决方案:

(1)“心跳”机制。在每个页面上包含一个脚本,该脚本将通过一些虚拟 ajax 请求“ping”服务器,例如:

<script>
   setInterval(ping, 60000); // based on comment by John
   function ping()
   {
       $.get('/do/nothing');
   }
</script>

这样,只要浏览器窗口打开,会话就不会过期。

(2) 在每个 ajax 请求上检查响应的状态。如果响应包含“401 未授权”代码(或任何其他与 200 不同的代码),则意味着会话已过期,而不是将响应加载到页面中的某个对话框中,而是将用户重定向到登录页面。

基于cmets的结论:

最好的解决方案是将上述两种机制结合起来。只要页面显示在浏览器中,心跳机制将有助于保持会话处于活动状态。但 in 并不能保证这一点。当会话过期时,与服务器的连接可以中断并重新打开。所以无论如何你都应该检查响应状态。

【讨论】:

  • 你可以这样做 setInterval(ping,60000); 不建议将字符串传递给 setInterval,因为它相当于 eval()
  • 如果您希望它多次运行,还需要在 ping() 中再次调用 setInterval
  • 200以外的任何代码并不意味着会话已经过期。
  • 防止超时不是一个非常安全的选择。超时没问题。我们只需要它们正常工作:)
  • 达林,这是真的,但是 200 以外的代码意味着(在大多数情况下)发生了一些意外情况。无论如何,执行 ajax 请求的脚本应该会以某种方式解决这种情况。
猜你喜欢
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 2015-10-23
  • 2013-01-13
  • 1970-01-01
相关资源
最近更新 更多