【问题标题】:Re-Initialize context.User after FormsAuthenticationTicket timeoutFormsAuthenticationTicket 超时后重新初始化 context.User
【发布时间】:2012-02-08 21:27:13
【问题描述】:

在我们的应用程序中,我们实现了基于角色的表单身份验证。这已使用 RoleModule 处理,我们将角色数据保存在 cookie 中, 每次我们从cookie中读取数据并实例化IPrincipal对象。这段代码在Application_OnPostAcquireRequestState方法中执行:

 HttpApplication application = source as HttpApplication;
 HttpContext context = application.Context;

if (context.User.Identity.IsAuthenticated &&
      (!Roles.CookieRequireSSL || context.Request.IsSecureConnection))
{
//Read the roles data from the Roles cookie..

context.User = new CustomPrincipal(context.User.Identity, cookieValue);
Thread.CurrentPrincipal = context.User;
}

这会初始化context.User 对象。每次向服务器发出请求时,都会使用上述流程对用户进行身份验证。 在Application_EndRequest 中,我们使用当前主体对象数据更新角色cookie。

在我们的Global.asax 页面中有FormsAuthentication_OnAuthenticate 方法,我们在其中读取cookie,更新cookie,并更新 票过期了。另外,在这个方法中,如果票据过期,我们会尝试在会话对象中设置用户名值。

FormsAuthentication oldTicket = FormsAuthentication.Decrypt(context.Request.Cookies[FormsAuthentication.FormsCookieName].Value);
if(oldTicket != null)
{
    if(oldTicket.Expired)
    {
        try
        {
            HttpContext.Current.Session["UserName"] = userName;
        }
        catch
        {
            //Log error.
        }

    FormsAuthentication newTicket =  new FormsAuthenticationTicket(oldTicket.Version, oldTicket.Name, DateTime.Now,
            DateTime.Now.AddMinutes(30), oldTicket.IsPersistent, oldTicket.UserData);

    string encryptedTicket = FormsAuthentication.Encrypt(newTicket);
    HttpCookie httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    if (isPersistent)
    {
        httpCookie.Expires = DateTime.Now.AddMinutes(300);
    }
}

这是我们在 web.config 中的表单设置:

   <forms defaultUrl="Default.aspx" domain="" loginUrl="Login.aspx" name=".ASPXFORMSAUTH" timeout="20" slidingExpiration="true" />

会话超时为 20 分钟。

问题:如果用户闲置超过 30 分钟(即 FormsAuth 票证续订时间),context.User.Identity.IsAuthenticated 中的值 角色模块为falsecontext.User设置为NULL。现在,当用户请求一个页面时,他将被重定向到登录页面。但是,那 饼干还在。如果再次,用户尝试请求页面,context.User.IsAuthenticated 属性设置为true,用户将被带到 相应的页面。另外,在FormsAuthentication_OnAuthenticate 方法中,当我尝试设置会话值时,它会抛出一个错误,因为会话对象是NULL

我想在这里实现的是,在持久cookie的情况下,在auth票超时后,用户不应该被注销,即用户应该 重新认证。

我怎样才能做到这一点? 如果我没记错的话,设置context.User应该可以解决问题,但是我该怎么做呢?

其他信息:

票证到期后,我尝试请求页面,事件查看器显示错误消息:

Event code: 4005 
Event message: Forms authentication failed for the request. Reason: The ticket supplied has expired. 
Event time: 08-02-2012 20:02:05 
Event time (UTC): 08-02-2012 14:32:05 
Event ID: 048e3238ade94fd6a7289bac36d130ef 
Event sequence: 76 
Event occurrence: 2 
Event detail code: 50202 

Process information: 
Process ID: 21692 
Process name: w3wp.exe 
Account name: IIS APPPOOL\ASP.NET v4.0 Classic 

我使用的是标准机器密钥设置,存储在 web.config 中,而不是自动生成的。此外,我检查了所有错误的进程 ID 及其相同。

【问题讨论】:

    标签: asp.net cookies forms-authentication httpmodule formsauthenticationticket


    【解决方案1】:

    我终于解决了这个问题。发生的情况是,当 FormsAuthentication 票证超时时,FormsAuthentication_OnAuthenticate 无法设置 context.User 对象,正如 MSDN documentation 中为 Authenticate 事件指定的那样:

    如果您在执行期间未指定 User 属性的值 FormsAuthentication_OnAuthenticate 事件,由 使用 cookie 或 URL 中的表单身份验证票证。

    原因是我没有使用用户的用户名设置ticket.Name。它是一个空字符串。因此,可能是 Authenticate 事件无法获取用户的身份并创建 FormsIdentity 实例。作为一种解决方案,当我更新过期票时,我还创建了一个GenericIdentity 对象,然后使用它来设置context.User

    IIdentity identity = new GenericIdentity(username, "Forms");
    context.User = new CustomPrincipal(identity);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 2013-08-13
      • 2017-12-15
      • 1970-01-01
      相关资源
      最近更新 更多