How to force update custom user claims?

2019-04-10 07:04发布

问题:

I've got a custom claim added to my ApplicationUser class as follows:

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        if(Theme != null)
            userIdentity.AddClaim(new Claim("ThemeBundle", Theme.Bundle));

        return userIdentity;
    }

    public int? ThemeId { get; set; }
    [ForeignKey("ThemeId")]
    public virtual Theme Theme { get; set; }
}

I extended Identity like this:

public static class IdentityExtensions
{
    public static string GetThemeBundle(this IIdentity identity)
    {
        var claim = ((ClaimsIdentity) identity).FindFirst("ThemeBundle");
        // Test for null to avoid issues during testing
        return (claim != null) ? claim.Value : string.Empty;
    }
}

I update the model behind the claim from the following Action Method:

    public ActionResult ChangeTheme(int id)
    {
        var theme = _db.Themes.Find(id);
        if (theme == null)
            return HttpNotFound();

        var userId = User.Identity.GetUserId();
        var user = _db.Users.Find(userId);
        user.Theme = theme;
        _db.SaveChanges();

        return RedirectToAction("Index", "Home");
    }

I access it in a view (or elsewhere) like this:

User.Identity.GetThemeBundle()

When the user updates their "Theme" property with the "ChangeTheme" action, nothing happens until they log off and log back in.

I've spent all day mulling over more than the following QA's with no good result:

Update User Claim not Taking Effect. Why?

MVC 5 AddToRole requires logout before it works?

And thanks to @Brendan Green: ASP.NET Identity - Forcing a re-login with security stamp

So far the best I've got is that the page will refresh and the claim returns an empty string instead of the desired result, OR I redirect the user to the login screen. At least those are less ambiguous than nothing happening.

How on earth can I get the claim to update globally as soon as the user changes their "Theme" property? I'd settle for a good way to fully log the user off and back on if needed. Using the AuthenticationManager.Signout and .Signin methods doesn't quite do the trick.

回答1:

As of Asp.Net MVC 6 and Asp.Identity 3.0.0-rc1-final you could use Task SignInManager<TUser>.RefreshSignInAsync(TUser user); in order to do that.