我正在使用 ASP Identity 进行身份验证。 Statup.Auth.cs 的一部分如下所示:
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity:
(manager, user) =>
user.GenerateUserIdentityAsync(manager))
},
ExpireTimeSpan = TimeSpan.FromMinutes(Settings.Default.SessionExpireTimeoutInMinutes),
});
以及我的登录方法的一部分:
SignInStatus result = await this.SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
如果用户选择“记住我”选项,则在 30 天之内他不会被注销。如果他不选择此选项,他应该会在一小段时间(比如说 10 分钟)后自动注销。此时,无论用户是否选择该选项,他都会注销。
最佳答案
SecurityStampValidator
类中存在一个已知错误,该错误会阻止在重置身份验证 cookie 时保留 isPercient
属性。
问题是supposedly resolved因此您应该尝试更新所有软件包,但有些人仍然遇到问题。
解决此问题的一种方法是编写您自己的 SecurityStampValidator
类。您可以找到 Microsoft source code here 的版本.
这是我尝试过的一些似乎有效的代码(我添加了 AuthenticationProperties
并设置了 AllowRefresh
和 IsPersistent
属性):
using Microsoft.Owin.Security.Cookies;
using Owin;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Security;
namespace Microsoft.AspNet.Identity.Owin
{
/// <summary>
/// Static helper class used to configure a CookieAuthenticationProvider to validate a cookie against a user's security stamp
/// </summary>
public static class MySecurityStampValidator
{
/// <summary>
/// Can be used as the ValidateIdentity method for a CookieAuthenticationProvider which will check a user's security stamp after validateInterval
/// Rejects the identity if the stamp changes, and otherwise will call regenerateIdentity to sign in a new ClaimsIdentity
/// </summary>
/// <typeparam name="TManager"></typeparam>
/// <typeparam name="TUser"></typeparam>
/// <param name="validateInterval"></param>
/// <param name="regenerateIdentity"></param>
/// <returns></returns>
public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser>(TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentity)
where TManager : UserManager<TUser, string>
where TUser : class, IUser<string>
{
return OnValidateIdentity<TManager, TUser, string>(validateInterval, regenerateIdentity, (id) => id.GetUserId());
}
/// <summary>
/// Can be used as the ValidateIdentity method for a CookieAuthenticationProvider which will check a user's security stamp after validateInterval
/// Rejects the identity if the stamp changes, and otherwise will call regenerateIdentity to sign in a new ClaimsIdentity
/// </summary>
/// <typeparam name="TManager"></typeparam>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="validateInterval"></param>
/// <param name="regenerateIdentityCallback"></param>
/// <param name="getUserIdCallback"></param>
/// <returns></returns>
public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser, TKey>(TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentityCallback, Func<ClaimsIdentity, TKey> getUserIdCallback)
where TManager : UserManager<TUser, TKey>
where TUser :class, IUser<TKey>
where TKey : IEquatable<TKey>
{
return async (context) =>
{
DateTimeOffset currentUtc = DateTimeOffset.UtcNow;
if (context.Options != null && context.Options.SystemClock != null)
{
currentUtc = context.Options.SystemClock.UtcNow;
}
DateTimeOffset? issuedUtc = context.Properties.IssuedUtc;
// Only validate if enough time has elapsed
bool validate = (issuedUtc == null);
if (issuedUtc != null)
{
TimeSpan timeElapsed = currentUtc.Subtract(issuedUtc.Value);
validate = timeElapsed > validateInterval;
}
if (validate)
{
var manager = context.OwinContext.GetUserManager<TManager>();
var userId = getUserIdCallback(context.Identity);
if (manager != null && userId != null)
{
var user = await manager.FindByIdAsync(userId).ConfigureAwait(false);
bool reject = true;
// Refresh the identity if the stamp matches, otherwise reject
if (user != null && manager.SupportsUserSecurityStamp)
{
string securityStamp = context.Identity.FindFirstValue(Constants.DefaultSecurityStampClaimType);
if (securityStamp == await manager.GetSecurityStampAsync(userId).ConfigureAwait(false))
{
reject = false;
// Regenerate fresh claims if possible and resign in
if (regenerateIdentityCallback != null)
{
ClaimsIdentity identity = await regenerateIdentityCallback.Invoke(manager, user);
if (identity != null)
{
var isPersistent = context.Properties.IsPersistent;
AuthenticationProperties prop = new AuthenticationProperties();
prop.AllowRefresh = true; //without this, will log out after 30 minutes
prop.IsPersistent = isPersistent; //without this, will log out after 30 minutes, or whenever the browser session is ended
context.OwinContext.Authentication.SignIn(prop, identity);
}
}
}
}
if (reject)
{
context.RejectIdentity();
context.OwinContext.Authentication.SignOut(context.Options.AuthenticationType);
}
}
}
};
}
}
}
然后,假设您使用的是标准 MVC 项目,则可以通过在 Startup.Auth.cs
文件中将 SecurityStampValidator
更改为 MySecurityStampValidator
来使用它模板。
关于asp.net-mvc - ASP 身份登录 isPersistent 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28633142/