Back to: ASP.NET Core Identity Tutorials
Add or Remove User Claims in ASP.NET Core Identity
In this article, I will discuss managing user claims, i.e., how to add or remove user claims in ASP.NET Core Identity. Please read our previous article discussing How to Add or Remove Roles from a Given User using the ASP.NET Core Identity. At the end of this article, you will understand how to manage User Claims, i.e., How to Add or Remove Claims for a user using ASP.NET Core Identity API.
What are the Claims in ASP.NET Core Identity?
In ASP.NET Core Identity, a Claim is a piece of identity information about the user and is used for authorization decisions. A claim is a key-value pair representing specific user data. For example, a claim might have a type of Email and a value of user@example.com. So, it represents specific information about the user, such as their name, email address, role, permission level, or any other custom data relevant to the application. Common claim types are predefined in the System.Security.Claims.ClaimTypes class and include types like Name, Role, Email, etc. The following are the Key Features of Claims in ASP.NET Core Identity:
- Usage in Authentication and Authorization: Claims are checked during authorization processes. For example, an [Authorize] attribute in ASP.NET Core might be set up to allow access only if a user has a specific claim or a claim with a certain value.
- Claim Types and Values: Each claim consists of a type (a string that represents the kind of information stored) and a value (the actual information). For example, a claim type might be a role, and the value could be admin.
- Claim Storage: Claims are stored in the user’s authentication cookie or token and are available during the user’s session. This allows for efficient retrieval without the need to query the database frequently.
How User Claims Work in ASP.NET Core Identity?
- Upon Authentication: When users log in, their associated claims are typically retrieved from the database and added to the ClaimsPrincipal object, representing the authenticated user.
- During Requests: The authenticated user’s claims are available throughout the application for each HTTP request, typically through the User property in controllers or pages.
- In Authorization: The [Authorize] attribute in ASP.NET Core can use claims to determine whether a user can access a particular resource or execute a specific action.
Examples of Claims:
- Identity Claims: Username, Email Address, or User ID.
- Role Claims: User roles like Admin, User, Moderator, or Member.
- Permission Claims: Specific permissions like EditRole, DeleteRole, or CreateRole.
How to Add or Remove Claims for a User Using ASP.NET Core Identity?
In our next article, I will show how to implement Claim-Based Authorization in ASP.NET Core using Identity API. In this article, I will show you How to Add or Remove Claims for a user using ASP.NET Core Identity.
On the EditUser view, we have the Manage Claims button, as shown in the below image. We are not adding any Claims, so it is currently showing None. Once we have added claims for this user, those claims will be shown here.
When we click the Manage Claims button, we want to redirect it to the ManageUserClaims action method by passing the UserId. The ManageUserClaims view should look as shown below. This view displays the list of all claims in our application. If you want to add a claim to the user, check the checkbox. Otherwise, leave it unchecked. Already included claims will be in the selected mode. Suppose you select the Create and Edit Role checkboxes and click the Update button, as shown in the image below.
Once you click the Update button, it should add the Claims and redirect to the Edit user View page. This time, it should display the assigned Claims for this user, as shown in the image below.
User claims are stored in the AspNetUserClaims Identity table. So, once the Update button is clicked, the data should be updated in the underlying AspNetUserClaims database table, as shown in the below image.
Let us proceed and see how we can implement this in our application.
Modifying the Edit User View:
Modify the EditUser.cshtml view as follows. Here, we are adding the Manage Claims link to the ManageUserClaims action method of the Administration controller.
@model EditUserViewModel @{ ViewBag.Title = "Edit User"; } <h1>Edit User</h1> <form method="post" class="mt-3"> <input type="hidden" asp-for="Id" /> <div class="form-group row"> <label asp-for="Id" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="Id" disabled class="form-control"> </div> </div> <div class="form-group row"> <label asp-for="Email" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="Email" class="form-control"> <span asp-validation-for="Email" class="text-danger"></span> </div> </div> <div class="form-group row"> <label asp-for="UserName" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="UserName" class="form-control"> <span asp-validation-for="UserName" class="text-danger"></span> </div> </div> <div class="form-group row"> <label asp-for="FirstName" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="FirstName" class="form-control"> </div> </div> <div class="form-group row"> <label asp-for="LastName" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="LastName" class="form-control"> </div> </div> <div asp-validation-summary="All" class="text-danger"></div> <div class="form-group row"> <div class="col-sm-10"> <button type="submit" class="btn btn-primary">Update</button> <a asp-action="ListUsers" class="btn btn-primary">Cancel</a> </div> </div> <div class="card"> <div class="card-header"> <h3>User Roles</h3> </div> <div class="card-body"> @if (Model.Roles.Any()) { foreach (var role in Model.Roles) { <h5 class="card-title">@role</h5> } } else { <h5 class="card-title">None at the moment</h5> } </div> <div class="card-footer"> <a asp-action="ManageUserRoles" asp-controller="Administration" style="width:auto" asp-route-UserId="@Model.Id" class="btn btn-primary"> Manage Roles </a> </div> </div> <div class="card mt-3"> <div class="card-header"> <h3>User Claims</h3> </div> <div class="card-body"> @if (Model.Claims.Any()) { foreach (var claim in Model.Claims) { <h5 class="card-title">@claim</h5> } } else { <h5 class="card-title">None at the moment</h5> } </div> <div class="card-footer"> <a asp-action="ManageUserClaims" asp-controller="Administration" asp-route-UserId="@Model.Id" style="width:auto" class="btn btn-primary"> Manage Claims </a> </div> </div> </form>
Claims Store
In our application, we store claims in the following ClaimsStore static class. You could store them in a configuration file, database table, etc. So, create a class file named ClaimsStore.cs within the Models folder and copy and paste the following code. The Claim class belongs to the System.Security.Claims namespace. The Claim stores the data as a Key-Value pair, so the constructor of the Claim class expects two parameters, i.e., Claim Type and Its Value. Here, the GetAllClaims method returns three claims; the key and value have the same data.
using System.Security.Claims; namespace ASPNETCoreIdentityDemo.Models { public static class ClaimsStore { public static List<Claim> GetAllClaims() { return new List<Claim>() { // Initializes a new instance of the Claim class with the specified claim type, and value. new Claim("Create Role", "Create Role"), new Claim("Edit Role", "Edit Role"), new Claim("Delete Role", "Delete Role") }; } } }
UserClaim Class
Create a class file named UserClaim.cs within the Models folder and copy and paste the following code. This class contains two properties. The ClaimType is the claim, and the IsSelected property determines if the Claim is selected on the UI. This class will be used by the View Model to store the user’s claim information.
namespace ASPNETCoreIdentityDemo.Models { public class UserClaim { public string ClaimType { get; set; } public bool IsSelected { get; set; } } }
UserClaimsViewModel Class:
Create a class file named UserClaimsViewModel.cs within the Models folder and copy and paste the following code. This UserClaimsViewModel class carries the data from the controller action to the view and vice versa. There is a one-to-many relationship between the user and the claim. That means one user can have many claims.
namespace ASPNETCoreIdentityDemo.Models { public class UserClaimsViewModel { public UserClaimsViewModel() { //To Avoid runtime exception, we are initializing the Cliams property Cliams = new List<UserClaim>(); } public string UserId { get; set; } public List<UserClaim> Cliams { get; set; } } }
HttpGet ManageUserClaims Action
Next, add the following HttpGet ManageUserClaims Action method within the Administration Controller. The following code is self-explained, so please read the comment lines for a better understanding.
[HttpGet] public async Task<IActionResult> ManageUserClaims(string UserId) { //First, fetch the User Details Based on the UserId var user = await _userManager.FindByIdAsync(UserId); if (user == null) { //handle if the User is not Exists in the database ViewBag.ErrorMessage = $"User with Id = {UserId} cannot be found"; return View("NotFound"); } //Storing the UserName in the ViewBag for Display Purpose ViewBag.UserName = user.UserName; //Create UserClaimsViewModel Instance var model = new UserClaimsViewModel { UserId = UserId }; // UserManager service GetClaimsAsync method gets all the current claims of the user var existingUserClaims = await _userManager.GetClaimsAsync(user); // Loop through each claim we have in our application // Call the GetAllClaims Static Method ClaimsStore Class foreach (Claim claim in ClaimsStore.GetAllClaims()) { //Create an Instance of UserClaim class UserClaim userClaim = new UserClaim { ClaimType = claim.Type }; // If the user has the claim, set IsSelected property to true, so the checkbox // next to the claim is checked on the UI if (existingUserClaims.Any(c => c.Type == claim.Type)) { userClaim.IsSelected = true; } //By default the IsSelected is False, no need to set as false //Add the userClaim to UserClaimsViewModel Instance model.Cliams.Add(userClaim); } return View(model); }
In the above code,
- The FindByIdAsync method finds and retrieves a user from the identity system based on the user’s unique identifier (ID).
- The GetClaimsAsync(user) method retrieves all claims associated with the given user.
- ClaimsStore.GetAllClaims() method will return all the claims associated with the application.
- Then, we check which claims have already been assigned to the user and set the IsSelected property value accordingly.
ManageUserClaims View
Next, add a view named ManageUserClaims.cshtml within the Views/Administration directory, and copy and paste the following code. The model for this view is UserClaimsViewModel.
@model UserClaimsViewModel <form method="post"> <div class="card"> <div class="card-header"> <h2>Manage User Claims</h2> <h2>User Name: @ViewBag.UserName</h2> </div> <div class="card-body"> @for (int i = 0; i < Model.Cliams.Count; i++) { <div class="form-check m-1"> <input type="hidden" asp-for="@Model.Cliams[i].ClaimType" /> <input asp-for="@Model.Cliams[i].IsSelected" class="form-check-input" /> <label class="form-check-label" asp-for="@Model.Cliams[i].IsSelected"> @Model.Cliams[i].ClaimType </label> </div> } <div asp-validation-summary="All" class="text-danger"></div> </div> <div class="card-footer"> <input type="submit" value="Update" class="btn btn-primary" style="width:auto" /> <a asp-action="EditUser" asp-route-UserId="@Model.UserId" class="btn btn-primary" style="width:auto">Cancel</a> </div> </div> </form>
HttpPost ManageUserClaims Action
Next, add the following HttpPost ManageUserClaims Action method within the Administration Controller. The following code is self-explained, so please read the comment lines for a better understanding.
[HttpPost] public async Task<IActionResult> ManageUserClaims(UserClaimsViewModel model) { //First fetch the User Details var user = await _userManager.FindByIdAsync(model.UserId); if (user == null) { ViewBag.ErrorMessage = $"User with Id = {model.UserId} cannot be found"; return View("NotFound"); } // Get all the user existing claims and delete them var claims = await _userManager.GetClaimsAsync(user); var result = await _userManager.RemoveClaimsAsync(user, claims); if (!result.Succeeded) { ModelState.AddModelError("", "Cannot remove user existing claims"); return View(model); } // Add all the claims that are selected on the UI var AllSelectedClaims = model.Cliams.Where(c => c.IsSelected) .Select(c => new Claim(c.ClaimType, c.ClaimType)) .ToList(); //If At least 1 Claim is assigned, Any Method will return true if (AllSelectedClaims.Any()) { //add a user to multiple claims simultaneously result = await _userManager.AddClaimsAsync(user, AllSelectedClaims); if (!result.Succeeded) { ModelState.AddModelError("", "Cannot add selected claims to user"); return View(model); } } return RedirectToAction("EditUser", new { UserId = model.UserId }); }
In this example,
- _userManager.FindByIdAsync(model.UserId): This method will return the User information based on the UserId from the AspNetUsers identity table.
- _userManager.GetClaimsAsync(user): This method retrieves the claims associated with a given user from the AspNetUserClaims table.
- _userManager.RemoveClaimsAsync(user, claims): This method removes a user from multiple claims. All the claims assigned to this user are removed from the AspNetUserClaims table.
- _userManager.AddClaimsAsync(user, AllSelectedClaims): This method is used to add a user to multiple claims in the AspNetUserClaims table.
That’s it. Now, run the application and test its functionality; it should work as expected.
In the next article, I will discuss Claims-Based Authorization in ASP.NET Core Identity. In this article, I explain How to Add or Remove User Claims in ASP.NET Core Identity. I hope you enjoy this article, Manage User Claims in ASP.NET Core Identity.