ASP.NET:如何检测身份验证超时

8

我看过多篇类似这篇文章的内容,它们解释了如何检测用户会话已超时。为了更清晰地表述,这些文章所指的是由以下web.config行定义的超时值:

<sessionState mode="InProc" cookieless="UseDeviceProfile" timeout="120" />

不多介绍这种方法,它涉及检查Session.IsNewSession是否为真以及会话cookie是否已经存在。但是我没有看到任何关于如何检测身份验证超时的文章 -- 这是由web.config中的这一行定义的:

<authentication mode="Forms">
    <forms loginUrl="~/Home/Customer" timeout="60" name=".ASPXAUTH" requireSSL="false" slidingExpiration="true" defaultUrl="~/Home/Index" cookieless="UseDeviceProfile" enableCrossAppRedirects="false"/>
</authentication>

许多在线文章,包括这篇SO文章,都说你的Session超时值通常应该是您认证超时值的两倍。因此,现在我的Session是120,我的Authentication是60。这意味着我永远不会遇到会话已超时但用户仍然通过身份验证认证的情况; 如果用户超时,这将是由于认证而不是会话。

因此,和其他人一样,我对如何向用户报告他们的会话已超时(但实际上是由于认证超时)很感兴趣。是否有人知道如何实现这一点或有任何在线资源可以指向解决方案?


抱歉,我有点困惑。你的问题是如何检测超时,还是如何向用户报告你已经检测到超时? - Ender
1
一旦我知道如何检测超时,向用户报告应该很简单。我对如何检测超时比如何报告超时更感兴趣。 - Matt
我也曾经遇到过这个问题,因为当用户被重定向到登录页面时,很难区分身份验证失败还是授权失败。- http://stackoverflow.com/questions/1352501/detecting-forms-authentication-timeout-in-login-page - RyanW
3个回答

1
我会在请求早期利用http管道并发送适当的响应。
我的回答来源是:

Professional ASP.NET 2.0 Security, Membership, and Role Management

一个HTTP模块可能会解决问题:

Web.config:

<configuration>
  <system.web>
    <httpModules>
      <add name="MyAuthModule" type="MyAssembly.Security.MyAuthModule, MyAssembly"/>

...

实际的HTTP模块:

/// <summary>
/// A module for detecting invalid authentication 
/// </summary>
/// <remarks>See "How To Implement IPrincipal" in MSDN</remarks>
public class MyAuthModule : IHttpModule
{
    #region IHttpModule Members
    void IHttpModule.Dispose() { }
    void IHttpModule.Init(HttpApplication context)
    {
        context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
    }
    #endregion


    /// <summary>
    /// Inspect the auth request...
    /// </summary>
    /// <remarks>See "How To Implement IPrincipal" in MSDN</remarks>
    private void context_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpApplication a = (HttpApplication)sender;
        HttpContext context = a.Context;

        // Extract the forms authentication cookie
        string cookieName = FormsAuthentication.FormsCookieName;
        HttpCookie authCookie = context.Request.Cookies[cookieName];

        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            // check if previously authenticated session is now dead
            if (authTicket != null && authTicket.expired)
            {
               // send them a Response indicating that they've expired.
            }
        }
    }
}

祝你好运!


这看起来非常有前途,我已经尝试了一下。但是当我的身份验证期限过期时,你提供的代码中的“authCookie”为空。这让我想知道“Expired”属性如何变为true。是否有可能authCookie不为空但仍然过期?谢谢。 - Matt
@mega-matt:很可能是真的。但对你的目的有影响吗?管道早期缺少auth cookie也将识别出过期的auth“会话”——浏览器不会返回过期的cookie。我当时是为了其他目的而使用这段代码,但我发现利用HTTP Pipeline是一项非常强大的技术... - Brett
你说得对,缺少auth cookie通常意味着认证期已过期。但在cookie创建之前呢?您提供的代码将在建立cookie之前运行。因此,当用户正在登录(未创建auth cookie)时,此代码将运行并继续将其重定向到登录页面(这是我计划在过期的auth情况下执行的操作)。因此,是的,auth cookie的缺失可能意味着auth会话已过期,但也可能意味着尚未创建cookie。有什么想法吗? - Matt
@mega-matt:好吧,说得对。由于会话状态获取发生在管道的后面,你或多或少被迫通过 cookie 进行管理。也许你可以在登录后删除一个“成功登录”的“会话 cookie”(没有过期日期)?该 cookie 的存在和身份验证 cookie 的缺失将标记即将过期的身份验证。如果他们关闭浏览器并回来,那么“成功登录”cookie 将消失,然后你就可以像往常一样让表单身份验证工作。这个解决方案与其他方案类似;但是,在任何重定向之前,你都能够检测到这种情况。 - Brett

1

这可能不是最佳方法,但这是我想到的一个方案。

在登录时,在会话中记录一个时间戳,标记用户登录的时间。在每个后续请求(也许在 global.asax BeginRequest 中?)中,将此时间戳与当前时间进行比较,并将其与身份验证超时进行匹配(Scott Hanselman 在此处 解释如何读取它)。

这是我“脑海中”的想法……


1
当您登录用户时,可以在用户的计算机上放置一个cookie,指示他们有一个会话。当用户到达登录页面(因为如果他们的会话过期,他们的登录也必须过期),请检查用户是否具有该cookie以及他们是否具有您希望他们拥有的任何会话密钥(如果这证明困难,请在他们登录时设置会话变量)。如果他们有cookie,但没有任何会话密钥,则表示他们的会话已过期。

我以前也用过这种方法。 - RyanW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接