Search code examples
c#asp.netasp.net-mvcasp.net-mvc-4asp.net-web-api

How to update a claim in ASP.NET Identity?


I'm using OWIN authentication for my MVC5 project. This is my SignInAsync

 private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            var AccountNo = "101";
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            identity.AddClaim(new Claim(ClaimTypes.UserData, AccountNo));
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, RedirectUri="Account/Index"}, identity);
        }

As you can see, i added AccountNo into the Claims list.

Now, how can I update this Claim at some point in my application? So far, i have this:

 public string AccountNo
        {

            get
            {
                var CP = ClaimsPrincipal.Current.Identities.First();
                var Account= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData);
                return Account.Value;
            }
            set
            {
                var CP = ClaimsPrincipal.Current.Identities.First();
                var AccountNo= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData).Value;
                CP.RemoveClaim(new Claim(ClaimTypes.UserData,AccountNo));
                CP.AddClaim(new Claim(ClaimTypes.UserData, value));
            }

        }

when i try to remove the claim, I get this exception:

The Claim 'http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata: 101' was not able to be removed. It is either not part of this Identity or it is a claim that is owned by the Principal that contains this Identity. For example, the Principal will own the claim when creating a GenericPrincipal with roles. The roles will be exposed through the Identity that is passed in the constructor, but not actually owned by the Identity. Similar logic exists for a RolePrincipal.

How does one remove and update the Claim?


Solution

  • I created a Extension method to Add/Update/Read Claims based on a given ClaimsIdentity

    namespace Foobar.Common.Extensions
    {
        public static class Extensions
        {
            public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return;
    
                // check for existing claim and remove it
                var existingClaim = identity.FindFirst(key);
                if (existingClaim != null)
                    identity.RemoveClaim(existingClaim);
    
                // add new claim
                identity.AddClaim(new Claim(key, value));
                var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
            }
    
            public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return null;
    
                var claim = identity.Claims.FirstOrDefault(c => c.Type == key);
    
                // ?. prevents a exception if claim is null.
                return claim?.Value;
            }
        }
    }
    

    and then to use it

    using Foobar.Common.Extensions;
    
    namespace Foobar.Web.Main.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                // add/updating claims
                User.AddUpdateClaim("key1", "value1");
                User.AddUpdateClaim("key2", "value2");
                User.AddUpdateClaim("key3", "value3");
            }
    
            public ActionResult Details()
            {
                // reading a claim
                var key2 = User.GetClaimValue("key2");          
            }
        }
    }