当
SecurityStampValidator
触发
regenerateIdentity
回调时,当前已认证的用户会重新使用非持久化登录重新登录。这是硬编码的,我不认为有任何直接控制它的方法。因此,登录会话仅在重新生成身份的时候运行到浏览器会话结束。
下面是一种方法,使登录持续,即使跨身份重建操作。该描述基于使用Visual Studio MVC ASP.NET Web项目模板。
首先,我们需要一种追踪持久化登录会话的方式,跨分离的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);
}
}
}
接下来,当用户登录请求一个持久会话时,我们需要添加“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
的任何人都需要传递isPersistent
标志。例如,在AccountController.SignInAsync
中对GenerateUserIdentityAsync
的调用将更改为:
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent },
await user.GenerateUserIdentityAsync(UserManager));
to
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent },
await user.GenerateUserIdentityAsync(UserManager, isPersistent));
最后,在
Startup.ConfigureAuth
方法中使用的
CookieAuthenticationProvider.OnValidateIdentity
委托需要一些关注,以在身份再生操作之间保留持久性细节。默认委托如下所示:
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),
regenerateIdentity: (manager, user) =>
user.GenerateUserIdentityAsync(manager, context.Identity.GetIsPersistent())
)(context);
var newResponseGrant = context.OwinContext.Authentication.AuthenticationResponseGrant;
if (newResponseGrant != null)
{
newResponseGrant.Properties.IsPersistent = context.Identity.GetIsPersistent();
}
}