asp.net-mvc - MVC Identity (2.0.1) 中的 regenerateIdentity/validateInterval 持续时间后忽略 ExpireTimeSpan

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

我一整天都在为这个问题挠头。我正在尝试在 MVC Identity 2.0.1 中设置“非常长”的登录 session 。 (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 现在仅作为“ session ”重新发布(仍然是正确的 cookie 名称)! 30 天的期限已经过去了。

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

我已经测试了删除“Provider”,然后一切都按预期工作,我可以在几个小时后回来,但我仍然可以正常登录。 我读到,最好的做法是使用邮票重新验证,所以我不确定如何继续。

最佳答案

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

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

首先,我们需要有一种方法来跟踪登录 session 在单独的 HTTP 请求中是持久的这一事实。这可以通过向用户身份添加“IsPersistent”声明来完成。以下扩展方法展示了执行此操作的方法。

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);
        }
    }
}

接下来,当用户登录请求持久 session 时,我们需要发出“IsPersistent”声明。例如,您的 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 的任何调用者现在都需要传入 isPercient 标志。例如,对 AccountController.SignInAsync 中的 GenerateUserIdentityAsync 的调用将更改为

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

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

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

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();
    }
}

关于asp.net-mvc - MVC Identity (2.0.1) 中的 regenerateIdentity/validateInterval 持续时间后忽略 ExpireTimeSpan,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23983726/

相关文章:

asp.net-mvc - Asp Net vNext 上的 Kestrel 不提供/下的索引页

asp.net - 在使用密码登录后调用电话时,退出无法正常工作?

c# - 使用 ASP.NET 重置密码时 token 无效

identity - 使用刷新 token 时出现 Invalid_Grant 错误

c# - 用户信息端点未找到 openid 范围

javascript - 如何将文本框值传递给 Javascript 函数?

asp.net-mvc - 如何禁用我的 @Html.ListBoxFor()

c# - Entity Framework 5 中的代码拳头枚举未添加到数据库

c# - ASP.NET Core 2.2 在 DbContext 中获取 userId

asp.net-mvc - 为什么 UserManager.CreateIdentityAsync() 寻找 IdentityRole 以及如何修复?