在MVC Identity(2.0.1)中的regenerateIdentity / validateInterval持续时间后忽略ExpireTimeSpan

时间:2014-06-01 19:40:35

标签: asp.net-mvc asp.net-identity identity

整天都在这个问题上摸不着头脑。我正在尝试在MVC Identity 2.0.1中设置“非常长”的登录会话。 (30天)。

我使用以下cookie启动:

      app.UseCookieAuthentication(new CookieAuthenticationOptions
        {

            SlidingExpiration = true,
            ExpireTimeSpan = System.TimeSpan.FromDays(30),
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/My/Login"),
            CookieName = "MyLoginCookie",
            Provider = new CookieAuthenticationProvider
            {                           
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),

                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

总的来说,工作正常。因此,cookie设置为30天,所有看起来都很好。

如果我关闭浏览器并在“validateInterval”持续时间过去之后回来(这里30分钟)我仍然登录,但是cookie现在仅作为“会话”重新发布(仍然是正确的cookie名称)! 30天的到期时间已经过去了。

如果我现在关闭浏览器/再次重新打开,我将不再登录。

我已经测试过删除“提供商”并且所有工作都按预期进行,我可以在几个小时后回来并且我仍然可以正常登录。 我读到最好使用印章重新验证,所以我不确定如何继续。

2 个答案:

答案 0 :(得分:36)

SecurityStampValidator触发regenerateIdentity回调时,当前经过身份验证的用户将使用非持久性登录重新登录。这是硬编码的,我不相信有任何方法可以直接控制它。因此,登录会话将仅在您重新生成身份时运行的浏览器会话结束时继续。

这是一种使登录持久化的方法,即使在身份再生操作中也是如此。此描述基于使用Visual Studio MVC ASP.NET Web项目模板。

首先,我们需要有一种方法来跟踪登录会话在不同的HTTP请求中是否持久的事实。这可以通过添加&#34; IsPersistent&#34;声称用户的身份。以下扩展方法显示了执行此操作的方法。

public static class ClaimsIdentityExtensions
{
    private const string PersistentLoginClaimType = "PersistentLogin";

    public static bool GetIsPersistent(this System.Security.Claims.ClaimsIdentity identity)
    {
        return identity.Claims.FirstOrDefault(c => c.Type == PersistentLoginClaimType) != null;
    }

    public static void SetIsPersistent(this System.Security.Claims.ClaimsIdentity identity, bool isPersistent)
    {
        var claim = identity.Claims.FirstOrDefault(c => c.Type == PersistentLoginClaimType);
        if (isPersistent)
        {
            if (claim == null)
            {
                identity.AddClaim(new System.Security.Claims.Claim(PersistentLoginClaimType, Boolean.TrueString));
            }
        }
        else if (claim != null)
        {
            identity.RemoveClaim(claim);
        }
    }
}

接下来我们需要制作&#34; IsPersistent&#34;当用户登录请求持久会话时声明。例如,您的ApplicationUser类可能有一个GenerateUserIdentityAsync方法,可以更新该方法以获取isPersistent标记参数,以便在需要时进行此类声明:

public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, bool isPersistent)
{
    var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
    userIdentity.SetIsPersistent(isPersistent);
    return userIdentity;
}

ApplicationUser.GenerateUserIdentityAsync的所有来电者现在都需要传递isPersistent标志。例如,GenerateUserIdentityAsync中对AccountController.SignInAsync的调用将从

更改
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, 
    await user.GenerateUserIdentityAsync(UserManager));

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent },
    await user.GenerateUserIdentityAsync(UserManager, isPersistent));

最后,CookieAuthenticationProvider.OnValidateIdentity方法中使用的Startup.ConfigureAuth委托需要注意保留身份重新生成操作中的持久性详细信息。默认委托如下所示:

OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
    validateInterval: TimeSpan.FromMinutes(20),
    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))

可以更改为:

OnValidateIdentity = async (context) =>
{
    await SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromMinutes(20),
        // Note that if identity is regenerated in the same HTTP request as a logoff attempt,
        // the logoff attempt will have no effect and the user will remain logged in.
        // See https://aspnetidentity.codeplex.com/workitem/1962
        regenerateIdentity: (manager, user) =>
            user.GenerateUserIdentityAsync(manager, context.Identity.GetIsPersistent())
    )(context);

    // If identity was regenerated by the stamp validator,
    // AuthenticationResponseGrant.Properties.IsPersistent will default to false, leading
    // to a non-persistent login session. If the validated identity made a claim of being
    // persistent, set the IsPersistent flag to true so the application cookie won't expire
    // at the end of the browser session.
    var newResponseGrant = context.OwinContext.Authentication.AuthenticationResponseGrant;
    if (newResponseGrant != null)
    {
        newResponseGrant.Properties.IsPersistent = context.Identity.GetIsPersistent();
    }
}

答案 1 :(得分:4)

ASP.NET Identity 2.2中修复了此错误。见https://aspnetidentity.codeplex.com/workitem/2319