Search code examples
asp.netasp.net-mvcasp.net-identity-2

Add and keep a "temporary" claim


On a MVC5 web app I'm using Asp.net Identity. When the user register, I add some claims, they are saved on the database and restored when the user log in. This works perfectly. Now, based on a parameter (a checkbox on the login page), I want to, when the user login add a specific Claim to the user. But there is a catch: this Claim will only exist on that user specific session (if the same user log on another browser instance or device and do not check the checkbox, he wont have that claim). I am not using and wish not to rely on asp.net Session.

I implemented this easily, just adding the Claim when calling AuthenticationManager.SignIn:

private async Task SignInAsync(CustomUser user, bool isPersistent, bool myCustomTemporaryClaim)
{
    var identities = await user.GenerateUserIdentityAsync(UserManager);

    if (myCustomTemporaryClaim)
    {
        identities.AddClaim(new Claim(CustomClaimTypes.MyCustomTemporaryClaim, "true"));
    }

    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identities);
}

This works fine. But the default asp.net identity implementation that comes on the VS template is configured to "refresh" the identity every 30 minutes. When this happens, I loose my Custom claim. So, what I would like to know is, it is possible to "intercept" and get my custom claim value before asp.net identity re-generate the cookie?

I can just remove the regenerateIdentityCallback but I do not know what the outcome of this may be.


Solution

  • I'm sure you've worked out what to do by now, but just in case anyone else stumbles across this thread, I think you just need to move the AddClaim into the GenerateUserIdentityAsync method. Then when the refresh occurs and regenerateIdentityCallback is called, your claim will just be added back in.

    For your condition myCustomTemporaryClaim, you could include a parameter in GenerateUserIdentityAsync. See this post for more detail on how to do this and how you'd need to change the callback: ExpireTimeSpan ignored after regenerateIdentity / validateInterval duration in MVC Identity (2.0.1)

    i.e. (note I'm using int for my UserId)

    private async Task SignInAsync(ApplicationUser user, bool isPersistent, bool myCustomTemporaryClaim)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        var identity = await user.GenerateUserIdentityAsync(UserManager, myCustomTemporaryClaim);
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }
    

    and

    public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager, bool myCustomTemporaryClaim)
        {
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
    
            if (myCustomTemporaryClaim)
            {
                userIdentity.AddClaim(new Claim(CustomClaimTypes.MyCustomTemporaryClaim, Convert.ToString(true)));
            }
    
            return userIdentity;
        }
    }
    

    Incidentally, the reason I ended up reading your post is because I kept losing my custom claim when calling SignInAsync, so I just replaced this

    var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    

    with this

    var identity = await user.GenerateUserIdentityAsync(UserManager);