Add or Remove Roles from a User in ASP.NET Core Identity

How to Add or Remove Roles from a Given User in ASP.NET Core Identity

In this article, I will discuss Managing User Roles, i.e., How to Add or Remove Roles from a Given User using the ASP.NET Core Identity. Please read our previous article discussing How to Enforce ON DELETE NO ACTION in ASP.NET Core Identity. This is similar to How to Add or Remove Users from a Given Role using the ASP.NET Core Identity.

Add or Remove Role from a Given User in ASP.NET Core Identity:

So, what we want to do is, in the EditUser View, we need to provide a button for Adding or Removing Roles from the given user, as shown in the image below. If any Roles are already given to this User, those roles list will also be displayed here.

Add or Remove Role from a Given User in ASP.NET Core Identity

Once we click on the Manage Roles button, it will open the following page. Here, it will display all the Roles. For roles already assigned to this user, their checkbox should be selected, and for those not assigned, their checkbox will be unselected.

Managing User Roles, i.e., How to Add or Remove Roles from a Given User using the ASP.NET Core Identity

Once the Update button is clicked, the data should be updated in the underlying AspNetUserRoles database table. Let us proceed and see how we can implement this in our application.

Modifying EditUser View:

Modify the EditUser.cshtml View as follows. Here, we have added the link for Manage Roles. When we click on the Manager Roles link, it will redirect to the ManageUserRoles action method of the AdministrationController.

@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 href="#" style="width:auto" class="btn btn-primary">
                Manage Claims
            </a>
        </div>
    </div>
</form>
Creating UserRolesViewModel:

Create a model that will be used to pass data between your view and the controller. So, create a class file named UserRolesViewModel.cs and copy and paste the following code:

namespace ASPNETCoreIdentityDemo.Models
{
    public class UserRolesViewModel
    {
        public string RoleId { get; set; }
        public string RoleName { get; set; }
        public string? Description { get; set; }
        public bool IsSelected { get; set; }
    }
}

In this class,

  • The RoleId property will hold the ID of the Role, which we require when updating the data.
  • The RoleName property will display the Role Name on the view. The Description property is a custom property we created to hold the role’s description.
  • IsSelected property is required to determine if the role is selected to be assigned to the given user.

Note: We could include the UserId property in this class, but as far as this view is concerned, there is a one-to-many relationship from User to Roles. So, to not repeat UserId for each Role, we will use ViewBag to pass UserId from the controller to the view.

ManageUserRoles GET Action Method:

Next, add the following ManageUserRoles Get Action Method within the Administration controller. This model will retrieve all the Roles from the database, check which roles are already assigned to the user, and then pass the model data to the corresponding view.

[HttpGet]
public async Task<IActionResult> ManageUserRoles(string UserId)
{
    //First Fetch the User Information from the Identity database by user Id
    var user = await _userManager.FindByIdAsync(UserId);

    if (user == null)
    {
        //handle if User Not Found in the Database
        ViewBag.ErrorMessage = $"User with Id = {UserId} cannot be found";
        return View("NotFound");
    }

    //Store the UserId in the ViewBag which is required while updating the Data
    //Store the UserName in the ViewBag which is used for displaying purpose
    ViewBag.UserId = UserId;
    ViewBag.UserName = user.UserName;

    //Create a List to Hold all the Roles Information
    var model = new List<UserRolesViewModel>();

    //Loop Through Each role and populate the model 
    foreach (var role in await _roleManager.Roles.ToListAsync())
    {
        var userRolesViewModel = new UserRolesViewModel
        {
            RoleId = role.Id,
            RoleName = role.Name,
            Description = role.Description
        };

        //Check if the Role is already assigned to this user
        if (await _userManager.IsInRoleAsync(user, role.Name))
        {
            userRolesViewModel.IsSelected = true;
        }
        else
        {
            userRolesViewModel.IsSelected = false;
        }

        //Add the userRolesViewModel to the model
        model.Add(userRolesViewModel);
    }

    return View(model);
}

In this example,

  • _userManager.FindByIdAsync(UserId): This method will return the user information based on the UserId from the AspNetUsers table.
  • _roleManager.Roles.ToListAsync(): This method will return all the roles from the AspNetRoles table.
  • _userManager.IsInRoleAsync(user, role.Name): This method will check whether the role has already been assigned to this user. If yes, set the IsSelected property of the UserRolesViewModel to true; otherwise, set this property value to false.
  • Here, we are also storing the UserId and UserName in the ViewBag.
ManageUserRoles View:

Next, add the ManageUserRoles.cshtml view within the /Views/Administration directory and copy and paste the following code.

@model List<UserRolesViewModel>

@{
    var UserId = ViewBag.UserId;
}

<form method="post">
    <div class="card">
        <div class="card-header">
            <h3>User: @ViewBag.UserName </h3>
        </div>
        <div class="card-header">
            <h4>Manage Roles</h4>
        </div>
        <div class="card-body">
            @for (int i = 0; i < Model.Count; i++)
            {
                <div class="form-check m-1">
                    <input type="hidden" asp-for="@Model[i].RoleId" />
                    <input type="hidden" asp-for="@Model[i].RoleName" />
                    
                    <input asp-for="@Model[i].IsSelected" class="form-check-input" />
                    <label class="form-check-label" asp-for="@Model[i].IsSelected">
                        @Model[i].RoleName - @Model[i].Description
                    </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="@UserId"
               class="btn btn-primary" style="width:auto">Cancel</a>
        </div>
    </div>
</form>
ManageUserRoles Post Action Method:

Next, add the following ManageUserRoles Post Action Method within the Administration controller.

[HttpPost]
public async Task<IActionResult> ManageUserRoles(List<UserRolesViewModel> model, string UserId)
{
    var user = await _userManager.FindByIdAsync(UserId);

    if (user == null)
    {
        ViewBag.ErrorMessage = $"User with Id = {UserId} cannot be found";
        return View("NotFound");
    }

    //fetch the list of roles the specified user belongs to
    var roles = await _userManager.GetRolesAsync(user);

    //Then remove all the assigned roles for this user
    var result = await _userManager.RemoveFromRolesAsync(user, roles);

    if (!result.Succeeded)
    {
        ModelState.AddModelError("", "Cannot remove user existing roles");
        return View(model);
    }

    List<string> RolesToBeAssigned = model.Where(x => x.IsSelected).Select(y => y.RoleName).ToList();

    //If At least 1 Role is assigned, Any Method will return true
    if (RolesToBeAssigned.Any())
    {
        //add a user to multiple roles simultaneously

        result = await _userManager.AddToRolesAsync(user, RolesToBeAssigned);
        if (!result.Succeeded)
        {
            ModelState.AddModelError("", "Cannot Add Selected Roles to User");
            return View(model);
        }
    }

    return RedirectToAction("EditUser", new { UserId = UserId });
}

In this example,

  • _userManager.FindByIdAsync(UserId): This method will return the User information based on the UserId from the AspNetUsers identity table.
  • _userManager.GetRolesAsync(user): This method retrieves the roles associated with a given user.
  • _userManager.RemoveFromRolesAsync(user, roles): This method removes a user from multiple roles simultaneously. All the roles assigned to this user are removed from the AspNetUserRoles table.
  • _userManager.AddToRolesAsync(): This method allows a user to add multiple roles simultaneously.

That’s it. Now, run the application and test its functionality; it should work as expected.

In the next article, I will discuss Managing User Claims in ASP.NET Core Identity. In this article, I explain How to Add or Remove Roles from a Given User using the ASP.NET Core Identity. I hope you enjoy this article, Managing User Roles in ASP.NET Core Identity.

Registration Open For New Online Training

Enhance Your Professional Journey with Our Upcoming Live Session. For complete information on Registration, Course Details, Syllabus, and to get the Zoom Credentials to attend the free live Demo Sessions, please click on the below links.

Leave a Reply

Your email address will not be published. Required fields are marked *