I've just taken a .NET Framework application and converted it to .NET Core. When importing the data from the old User-table, the SecurityStamp values were lower-case GUIDs, e.g. '0e124deb-8392-4dcc-bce7-38dcc48569a2'. When a user change their password, they get a new SecurityStamp. Now they are uppercase, e.g. 'WHBXXXSQEIDVA7KF3T6AJJJ3AHWWUSYE'.
The users with the new SecurityStamp do not have any problems. Should I just wipe the SecurityStamp column in the user table? Is there a new SecurityStamp created when the user log in the next time? I've had a hard time finding documentation on Identity on this level.
A new security stamp is only created if the user change their password or unlink from an external login.
Cookie is validated on a time interval of 30 mins by default. since you are using the latest .net-core version you may use the following code snippet in ConfigureServices()
in startup.cs
to extend your validation time.
If time is set to 0 it will validate in every request
services.Configure<SecurityStampValidatorOptions>(options =>
{
// This is the key to control how often validation takes place
options.ValidationInterval = TimeSpan.FromMinutes(30);
});
Note: UserManager allows you to update your security stamp using the method
userManager.UpdateSecurityStampAsync(user)
. if you use this after login, validation will fail most probably.
Finally if you want to handle this behavior in your own way, you can write your own validator and wireup in the middleware
services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.Events.OnValidatePrincipal = LastChangedValidator.ValidateAsync;
});
public static class LastChangedValidator
{
public static async Task ValidateAsync(CookieValidatePrincipalContext context)
{
// you can use your own logic
/* var userRepository = context.HttpContext.RequestServices.GetRequiredService<IUserRepository>();
var userPrincipal = context.Principal;
// Look for the last changed claim.
string lastChanged;
lastChanged = (from c in userPrincipal.Claims
where c.Type == "LastUpdated"
select c.Value).FirstOrDefault();
if (string.IsNullOrEmpty(lastChanged) ||
!userRepository.ValidateLastChanged(userPrincipal, lastChanged))
{
context.RejectPrincipal();
await context.HttpContext.Authentication.SignOutAsync("MyCookieMiddlewareInstance");
} */
}
}
Or else you can handle the ValidatePrincipal()
by overriding the method using the following
public class CustomCookieHandler: CookieAuthenticationEvents
{
public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
return base.ValidatePrincipal(context);
}
}