Ответ 1
Когда SecurityStampValidator
запускает обратный вызов regenerateIdentity
, текущий аутентифицированный пользователь получает повторную подписку с непостоянным входом в систему. Это жестко закодировано, и я не верю, что есть какой-либо способ напрямую его контролировать. Таким образом, сеанс входа в систему будет продолжаться только до конца сеанса браузера, который вы выполняете в точке, в которой регенерируется идентификатор.
Ниже приведен подход, позволяющий сделать логин постоянным, даже при выполнении операций регенерации идентичности. Это описание основано на использовании шаблонов веб-проектов Visual Studio MVC ASP.NET.
Сначала нам нужно иметь возможность отслеживать тот факт, что сеанс регистрации является постоянным в разных 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
. Например, вызов 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();
}
}