ASP.NET Identity, add another user to role instantly (they don't have to log out and in again)
Starting from the bottom of your question. User.IsInRole()
goes into user cookie and checks what roles are stored in that cookie. Hence it requires relogin for changes to take effect. And yes, you are correct in saying that UserManager.IsInRole()
checks with database, not with the cookie.
To make sure role changes are applied immediately you need to check for change in roles on every request. To do that in Startup.Auth.cs
find this line:
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(0), // <-- This is zero. Check on every request
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
This is a framework's way of updating cookie. By default validateInterval
is set for 30 minutes. If you set it to zero, the system will create a new cookie with updated roles on every request. This might be too much DB-load if you have enough users hitting your system at the same time. So I'd increase the timespan to 30-seconds-1-2minutes.
This feature was built as a way to logout all sessions by a single password change. But also works well for your purposes.
In ASP.NET Core, SignInManager.RefreshSignInAsync() solves this.
For ASP.NET Core Identity 2 the solution is to use:
services.Configure<SecurityStampValidatorOptions>(options =>
{
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
To force an update every minute or use TimeSpan.Zero to force an update everytime the user accesses the page (notice that everytime a database request is performed).
Also make sure that if you overwrite the cookie events do not use:
services.ConfigureApplicationCookie(options =>
{
options.Events = new CookieAuthenticationEvents(){
...
};
}
But overwrite the Events you need directly as otherwise validation is not called:
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = ctx => {
...
};
}