简体   繁体   中英

Remove claims from user

I am using ASP.NET Identity (v2) with Entity Framework. I am building a page with several checkboxes, each representing a claim. On a button click ( SavePrivileges function in my example) I would like to adjust claims of a given user according to the state of my checkboxes, ie remove claims, which are not checked, and add claims, which are checked.

Adding claims is working OK. However, I seem to be unable to remove claims from the user. Upon calling manager.RemoveClaim I get an InvalidOperationException saying that collection has changed. I actually get this exception even if I do not modify the user.Claims collection.

Here is my simplified example scenario:

    protected void SavePrivileges(string userId)
    {
        const string claim1Type = "...";
        const string claim2Type = "...";
        const string claim1Value = "...";
        const string claim2Value = "...";

        var store = new UserStore<IdentityUser>();
        var manager = new UserManager<IdentityUser>(store);
        var user = manager.FindById(userId);

        // Lists to keep track of changes
        var removed = new List<Claim>();
        var added = new List<Claim>();

        bool claim1Checked = CheckBox1.Checked;
        bool claim2Checked = CheckBox2.Checked;

        bool claim1Possesed = user.Claims.FirstOrDefault(claim => claim.ClaimValue == claim1Value &&
                                                                  claim.ClaimType  == claim1Type) != null;
        bool claim2Possesed = user.Claims.FirstOrDefault(claim => claim.ClaimValue == claim2Value &&
                                                                  claim.ClaimType  == claim2Type) != null;

        if (claim1Checked && !claim1Possesed)
        {
            added.Add(new Claim(claim1Type, claim1Value));
        }
        else if (!claim1Checked && claim1Possesed)
        {
            removed.Add(new Claim(claim1Type, claim1Value));
        }
        // + The same for claim2...

        // Remove extra claims
        foreach (Claim claim in removed)
        {
            manager.RemoveClaim(user.Id, claim);
        }
        // Add new claims
        foreach (Claim claim in added)
        {
            IdentityUserClaim identityUserClaim = new IdentityUserClaim { ClaimType = claim.Type, ClaimValue = claim.Value };
            user.Claims.Add(identityUserClaim);
        }

        // Save the result
        var result = manager.Update(user);
        if (result.Succeeded)
        {
            store.Context.SaveChanges();
        }
    }

Thanks for any help.

I have found a solution eventually, however, it is not ellegant in any way. If anyone comes up with a better solution, I will still be glad to see it.

foreach (Claim claim in removed) {
    var claimCollection = store.Context.Entry(user).Collection(u => u.Claims).CurrentValue;
    var storedClaim = claimCollection.FirstOrDefault(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value && c.UserId == user.Id);
    if (storedClaim != null)
        store.Context.Entry(storedClaim).State = EntityState.Deleted;
}

This worked well for me. Hope this helps!

user.Claims.ToList().ForEach(claim => Context.Entry(claim).State = 
                             System.Data.Entity.EntityState.Deleted);

Context.SaveChanges();

I have swapped over to excellent package ElCamino.AspNet.Identity.AzureTable which provides a Azure Table storage based implementation to replace the standard Microsoft.AspNet.Identity.EntityFramework Entity Framework based storage of Identity.

With the ElCamino.AspNet.Identity.AzureTable package installed the normal userManager.RemoveClaimAsync works as expected. From this, and a look at where the error occurs in the standard package, I suspect it is a bug in Microsoft.AspNet.Identity.EntityFramework.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM