6

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.

Community
  • 1
  • 1
Methodician
  • 2,396
  • 5
  • 30
  • 49
  • If you change the security stamp in the user table, that will invalidate the cookie / token and cause the next page request to force a reauth. See http://stackoverflow.com/questions/24570872/asp-net-identity-forcing-a-re-login-with-security-stamp – Brendan Green Jan 25 '16 at 23:57
  • Hmm... Not sure the trade off of lowering the ValidateInterval is very well worth it and it looks like setting it to zero isn't even an option since it messes up other functionality (like users not being able to log off)... For now I'm just using a RedirectToAction to send the user immediately to the login screen. Not the most elegant, but it does the trick for now. – Methodician Jan 26 '16 at 17:39

1 Answers1

6

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.

erick2red
  • 1,312
  • 1
  • 14
  • 19
  • 2
    This works, [but seemingly only for the currently logged in user](https://stackoverflow.com/q/51571852/590790), begging the question why the user can be passed at all then. If I pass a different user, the currently logged in user becomes logged in as that user instead. – Steven Jeuris Jul 30 '18 at 12:09