Permission-Based Authorization in ASP.NET Core – Complete User Management Guide in .NET 5

Setting up Permissions to access your resources is always a crucial part of your application’s security. In this article, we will implement Permission-Based Authorization in ASP.NET Core that builds upon the concept of Claim-Based Authorization in ASP.NET Core. As usual, we will be building this application right from scratch to get some detailed knowledge about the whole scenario and how it would actually help you secure your projects. You can find the complete source code of the implementation here.
Previously, we built an implementation for Custom User Management where we extended the IdentityUser class and defined custom properties like First Name, Last name, Profile Picture. etc. In this tutorial, we will go a step ahead and implement Permissions for Each User Roles. It is recommended to go through the previous article to get a complete picture of User Management and Securing ASP.NET Core Web Applications.
Let me set up the scenario. We have an application, say Stock Management that is to be secured with access levels. For instance, our application has features that can add new products, view product details, delete/modify products. As an ideal business requirement, not all the users should have the permissions to do everything, right? Admins can Add, Edit Products. Basic users can only view the product. Super-Admin can do whatever he wants to. So, this is our requirement. What’s your first approach to it? Role-Based Authorization is the most common and easy approach that would come into your mind naturally.
Please note that this is the exact implementation of Permission Management that is already implemented in the ASP.NET Core Hero Boilerplate Template (.NET 5 Clean Architecture Template). If you haven’t checked out the Boilerplate template yet, read about it here.
What’s Role-Based Authorization?
Role-Based Authorization in ASP.NET Core is a way to restrict/allow users to access specific resources in the application. The [Authorize] attribute when declared in the Controller or any action methods, restricts users bases on his/her role settings. For instance, the Delete method is accessible only to users who have the Role ‘SuperAdmin’ assigned to them, and so on. You are getting the point, yeah? Let me write down a simple code snippet to give a better picture.
[Authorize] public class ProductsController : Controller { public ActionResult View() { } [Authorize(Roles = "Administrator,SuperAdmin")] public ActionResult Create() { } [Authorize(Roles = "SuperAdmin")] public ActionResult Delete() { } [Authorize(Roles = "Administrator")] [Authorize(Roles = "SuperAdmin")] public ActionResult SpecialFeature() { } }
The above code is a super-easy demonstration of the concept mentioned.
Line #1 – This Attribute ensures that only Authorized (Logged In) Users can access the ProductsController. If you haven’t logged in and try to access the /products resource, you will be re-directed to the login page or throws a 401 UnAuthorized Exception.
Line #4 – Any Logged In User, no matter of what Role they belong to, can view the products list.
Line #6 – Only Administrators OR SuperAdmins can create new products.
Line #9 – Only SuperAdmin can delete resources.
Line #13 – Now, if there is a feature that can be accessed by users who are both Administrators as well as a SuperAdmin, this is how you would ideally achieve.
That’s almost covering everything in our requirement, right? But here is the catch, does this approach always work in practical scenarios?
Limitations of Role-Based Authorization
Imagine that we decided to add much more entities into our Stock Management Application like Customers, Orders, Suppliers, Companies. Now, let’s say that we need Admins for each department, like CustomerAdmins, OrderAdmins (you get the point). The list goes on and on as long as the application keeps scaling. As the Roles-Count increase, it becomes harder and harder to properly manage roles, right?
And imagine a scenario where you want to dynamically change the permission of a Role without touching the code. Quite not possible with Role-Based Authorization, yeah?
What about scenarios where you want to dynamically add/remove a particular role from existence? Wouldn’t this prove fatal since you have already hardcoded a role on to your controller?
What would you do if you wanted to implement a UI for User & Role Management?
These are the major limitations of Role-Based Authorization. We need a more flexible way to handle roles even though it keeps on increasing as well the make everything dynamic so that the super admin gets to change the permissions of each role on the go. This is where Permission-Based Authorization in ASP.NET Core comes in.
Permission-Based Authorization in ASP.NET Core
Let’s go with a mechanism that is finer than the Role-Based Authorization. We will introduce permissions at the role level so that only specific roles get to access protected resources. We will be using RoleClaims to set the permissions of roles.ASP.NET Core has some cool features to implement this easily.
Here a few advantages of taking this approach:
- Roles are no longer static to the code. It can be easily modified/added/deleted at runtime.
- The Permissions set to each role also can be modified easily at runtime.
- More Control on Authorization.
What we will build? (Screenshots Included)
Let’s get to know what our final implementation will look like. Here are a few screenshots of the final product.
List of all Registered Users
In this view, you get to see a list of all registered users. Note that the currently logged in user won’t be listed here. On Clicking the Action Dropdown, the SuperAdmin can Manage Roles for the corresponding user.

Manage User Roles
From the User List, the Superadmin will be able to assign roles to each user. For example, in the below screenshot, we will able to assign any of the available roles to the selected user. PS, This view is available for the super admin only.

Add New Roles
In this view, the super admin will be able to add new roles as and when required. This is where Permission Management comes into play.

Each of the Roles has Permissions assigned to itself. For instance, let’s select ‘Manage Permissions’ of the Admin Role. This would open up the permission management UI.

Manage Permissions – UI
This is where the magic happens. On this view, a super admin will be able to grant/revoke permissions to any roles available. This will be further drilled down to the users too. For instance, you can set the view, create, read, write, delete permissions of the product entity with ease, without having to touch the code. Pretty practical yeah? Let’s give the Role permissions to view and create products.

Now, let’s login as the previously modified user and open up the products page. You can see that only the Create and View Features are visible.

And this is what the super admin (with all permissions) would see on the product management page.

These are quite vital to any business out there. I believe such features should come out of the box with ASP.NET Core. One day. Hopefully.
However, let’s get started with the implementation without any further delay. You can find the complete source code here.
Getting Started with Permission-Based Authorization
So, the idea is simple. We will build a .NET 5 Web Application (MVC) with the default Identity package from Microsoft. To this project we will add features like :
- User List – To display all the registered users
- Roles List – To Display / Add Roles
- User – Roles Management – To assign various roles to each user.
- Default Seeding – Seed default roles and users on application startup
- Permission Management – Role-based permissions controller
- Dummy Products Management – To Create / Read / Modify Products (Note that this will not be implemented completely). The aim is to dynamically restrict users based on their roles from various actions on the Product Entity. For instance, only Admins can modify the data.
Let’s start by creating a new ASP.NET Core MVC Project / .NET 5 MVC (I am still worried about the naming convention Microsoft takes 😛 ). Note that we will be using the default Microsoft Identity in our project. Hence make sure that you select the Authentication Type as Individual accounts.

Create the project and wait for the scaffolding to get over.
Pre-Defined Roles
We would need some predefined roles to get started with. These roles will be available as soon as your application runs on the server. You guessed it right, we will be seeding some data to the database in a while as well. Let’s create a new folder Constants and add a new enum Roles.cs
public enum Roles { SuperAdmin, Admin, Basic }
These are the default roles that we would try to seed to the database as soon as the application fires up.
Similarly, let’s define permissions based on features. To get started, we assume that our System has a Products Entity with features like Create, View, Edit, Delete. These are more like CRUD Permissions.
public static class Permissions { public static List<string> GeneratePermissionsForModule(string module) { return new List<string>() { $"Permissions.{module}.Create", $"Permissions.{module}.View", $"Permissions.{module}.Edit", $"Permissions.{module}.Delete", }; } public static class Products { public const string View = "Permissions.Products.View"; public const string Create = "Permissions.Products.Create"; public const string Edit = "Permissions.Products.Edit"; public const string Delete = "Permissions.Products.Delete"; } }
Line #3 to #12 is a simple function that returns a list of permissions based on the string passed. We will be using this later for seeding permissions for the SuperAdmin. Remember the SuperAdmin would ideally be granted all the permissions.
Seeding Users and Roles
As we have defined the default users, roles, and a couple of permissions, let’s ensure that these data get into our database as soon as the application starts up. This process, in other words, is called Data Seeding. Create a New Folder named Seeds and add in a new class, DefaultRoles.cs
public static class DefaultRoles { public static async Task SeedAsync(UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager) { await roleManager.CreateAsync(new IdentityRole(Roles.SuperAdmin.ToString())); await roleManager.CreateAsync(new IdentityRole(Roles.Admin.ToString())); await roleManager.CreateAsync(new IdentityRole(Roles.Basic.ToString())); } }
The above snippet will create Default Roles into our application via the RoleManager Helper class of Identity.
Similarly, let’s add a mechanism to seed default users. For this demonstration, let’s seed 2 users – SuperAdmin and a Basic User.
public static class DefaultUsers { public static async Task SeedBasicUserAsync(UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager) { var defaultUser = new IdentityUser { UserName = "basicuser@gmail.com", Email = "basicuser@gmail.com", EmailConfirmed = true }; if (userManager.Users.All(u => u.Id != defaultUser.Id)) { var user = await userManager.FindByEmailAsync(defaultUser.Email); if (user == null) { await userManager.CreateAsync(defaultUser, "123Pa$$word!"); await userManager.AddToRoleAsync(defaultUser, Roles.Basic.ToString()); } } } public static async Task SeedSuperAdminAsync(UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager) { var defaultUser = new IdentityUser { UserName = "superadmin@gmail.com", Email = "superadmin@gmail.com", EmailConfirmed = true }; if (userManager.Users.All(u => u.Id != defaultUser.Id)) { var user = await userManager.FindByEmailAsync(defaultUser.Email); if (user == null) { await userManager.CreateAsync(defaultUser, "123Pa$$word!"); await userManager.AddToRoleAsync(defaultUser, Roles.Basic.ToString()); await userManager.AddToRoleAsync(defaultUser, Roles.Admin.ToString()); await userManager.AddToRoleAsync(defaultUser, Roles.SuperAdmin.ToString()); } await roleManager.SeedClaimsForSuperAdmin(); } } private async static Task SeedClaimsForSuperAdmin(this RoleManager<IdentityRole> roleManager) { var adminRole = await roleManager.FindByNameAsync("SuperAdmin"); await roleManager.AddPermissionClaim(adminRole, "Products"); } public static async Task AddPermissionClaim(this RoleManager<IdentityRole> roleManager, IdentityRole role, string module) { var allClaims = await roleManager.GetClaimsAsync(role); var allPermissions = Permissions.GeneratePermissionsForModule(module); foreach (var permission in allPermissions) { if (!allClaims.Any(a => a.Type == "Permission" && a.Value == permission)) { await roleManager.AddClaimAsync(role, new Claim("Permission", permission)); } } } }
Line #3 – #20: Creates a User with Basic Role. You can see that we are setting the email and username of this particular user in the code. Once the user is created/seeded, we add the user to the Basic Role.
Line #21 – #41: Similarly, we create another user and add it to Basic, Admin, and SuperAdmin Roles. Basically, this user is granted all roles.
Line #39: Here we add claims to the SuperAdmin user. The idea is that this super admin should have all permissions that exist in our system. Remember defining Product Permissions? We are going to build this seed in such a way that the SuperAdmin gets all of the product permissions.
Line #44: Get’s the role by name.
Line #49: Get all the existing claims that are already existing for the role.
Line #50: Here, we pass a string parameter “Product” to the GeneratePermissionsForModule method which will return a list of permissions for the Product Module (Create, Read, View, Delete, Modify). Remember we were working with this earlier?
Line #51 – #58: We loop through all the generated permissions, check if it doesn’t already exist within the role, and finally add it as a new claim to the specific, which in our case is ‘superadmin’.
Adding Claims to Roles – Seed Default Claims / Permissions for SuperAdmin
As we are done with creating our seed classes, let’s now hook it up with our application so that seed classes actually get executed when the application is fired. Program.cs / Main is the usual choice for placing the Seeding process as it’s the entry point of our application.
Open up Program.cs and replace the Main Method with the following code snippet.
public async static Task Main(string[] args) { var host = CreateHostBuilder(args).Build(); using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var logger = loggerFactory.CreateLogger("app"); try { var userManager = services.GetRequiredService<UserManager<IdentityUser>>(); var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>(); await Seeds.DefaultRoles.SeedAsync(userManager, roleManager); await Seeds.DefaultUsers.SeedBasicUserAsync(userManager, roleManager); await Seeds.DefaultUsers.SeedSuperAdminAsync(userManager, roleManager); logger.LogInformation("Finished Seeding Default Data"); logger.LogInformation("Application Starting"); } catch (Exception ex) { logger.LogWarning(ex, "An error occurred seeding the DB"); } } host.Run(); }
Line #13 – #15 is where we invoke the methods of the Seed classes that are responsible to write the default users/roles to the database. This is a pretty straightforward piece of code.
Displaying a List of Registered Users
With that out of the way, let’s get started with building the UI. We will start with creating a view for displaying all the registered users, except the currently logged in user. Note that this view is accessible only for logged-in users.
Create a New MVC Controller, UsersController. Make sure to include the [Authorize] decorator moving forward.
[Authorize] public class UsersController : Controller { private readonly UserManager<IdentityUser> _userManager; public UsersController(UserManager<IdentityUser> userManager) { _userManager = userManager; } public async Task<IActionResult> Index() { var currentUser = await _userManager.GetUserAsync(HttpContext.User); var allUsersExceptCurrentUser = await _userManager.Users.Where(a => a.Id != currentUser.Id).ToListAsync(); return View(allUsersExceptCurrentUser); } }
In this controller, we will have an Index Action Method which returns a list of users except for the current user. Nothing complicated. As the next step, let’s add in the view for the Index Method. This would be a view that takes in a list of users and displays the data in table format.
BEGINNER TIP: You can add a Corresponding View for any Action Method by right-clicking on the Method Name itself, and clicking on Add New View. Similarly, you can navigate to the created View easily by right-clicking the Method name and selecting ‘Go-To View’.
@using Microsoft.AspNetCore.Identity; @model IEnumerable<IdentityUser> <h1>User List</h1> <br /> <table class="table table-striped" id="userTable"> <thead> <tr> <th> User </th> <th> Email </th> <th style="width:10%"> Actions </th> </tr> </thead> <tbody> @foreach (var user in Model) { <tr> <td> <div class="row"> <div class="col-sm"> <a> @user.UserName </a> <br> <small> @user.Id </small> </div> </div> </td> <td> <a> @user.Email </a> </td> <td> <div class="btn-group"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Action </button> <div class="dropdown-menu shadow animated--grow-in"> <a style='margin-right:16px' asp-controller="userroles" asp-action="Index" asp-route-userId="@user.Id" class="dropdown-item"> <i class="fas fa-wrench"></i> Manage Roles </a> </div> </div> </td> </tr> } </tbody> </table>
Role Management UI
Next, we will be building a Role management UI that is accessible only by the Superadmin. The view would help us to list all the roles available as well as add new roles to the system. Let’s create a new controller, RolesController.
[Authorize(Roles ="SuperAdmin")] public class RolesController : Controller { private readonly RoleManager<IdentityRole> _roleManager; public RolesController(RoleManager<IdentityRole> roleManager) { _roleManager = roleManager; } public async Task<IActionResult> Index() { var roles = await _roleManager.Roles.ToListAsync(); return View(roles); } [HttpPost] public async Task<IActionResult> AddRole(string roleName) { if (roleName != null) { await _roleManager.CreateAsync(new IdentityRole(roleName.Trim())); } return RedirectToAction("Index"); } }
Line #1: Only SuperAdmins can access this controller.
Line #10 – #14: The index method returns a list of Roles back to the view.
Line #15 – #23: This is a POST method that facilitates the super admins to add new roles.
After that, let’s add a View for the Index Method of RolesController. This is also quite a simple UI with a Table and a provision to add new roles (textbox and a button).
@using Microsoft.AspNetCore.Identity; @model IEnumerable<IdentityRole> <h1>Roles</h1> <br /> <form method="post" asp-action="addrole" asp-controller="roles"> <div class="input-group"> <input name="roleName" class="form-control w-25"> <span class="input-group-btn"> <button class="btn btn-info">Add New Role</button> </span> </div> </form> <table class="table table-striped" id="roleTable"> <thead> <tr> <th> Role </th> <th> Id </th> <th style="width:10%"> Actions </th> </tr> </thead> <tbody> @foreach (var role in Model) { <tr> <td> @role.Name </td> <td> @role.Id </td> <td class="text-right"> <div class="btn-group"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Action </button> <div class="dropdown-menu shadow animated--grow-in"> <a class="dropdown-item"> <i class="fas fa-pencil-alt"></i> Edit </a> <form class="d-inline"> <a class="dropdown-item"><i class="fas fa-trash-alt"></i> Delete</a> </form> @if (role.Name != "SuperAdmin") { <a style='margin-right:16px' asp-controller="Permission" asp-action="Index" asp-route-roleId="@role.Id" class="dropdown-item"> <i class="fas fa-wrench"></i> Manage Permissions </a> } </div> </div> </td> </tr> } </tbody> </table>
Since we have implemented UIs for both Users and Roles, let’s add a feature where the superadmin can assign users to roles. Next-Up, let’s get started with the User-Role management.
Under the Models folder, add a new Class, UserRolesViewModel. This will be the Model (DTO) we send to the User-Role Management UI. It’s a simple structure that will hold the userId and a List of Roles assigned to the user.
public class ManageUserRolesViewModel { public string UserId { get; set; } public IList<UserRolesViewModel> UserRoles { get; set; } } public class UserRolesViewModel { public string RoleName { get; set; } public bool Selected { get; set; } }
With that out of the ways, let’s create a new controller, UserRolesController which again is accessible only by the SuperAdmins. This Controller will have 2 major methods – List All the Roles Available (this will be a checked list denoting the active roles as well for the user), and an update method to add the selected roles to the user.
Here is how it would look like:

Get the idea? Let’s see what the Controller would contain.
[Authorize(Roles = "SuperAdmin")] public class UserRolesController : Controller { private readonly SignInManager<IdentityUser> _signInManager; private readonly UserManager<IdentityUser> _userManager; private readonly RoleManager<IdentityRole> _roleManager; public UserRolesController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, RoleManager<IdentityRole> roleManager) { _userManager = userManager; _signInManager = signInManager; _roleManager = roleManager; } public async Task<IActionResult> Index(string userId) { var viewModel = new List<UserRolesViewModel>(); var user = await _userManager.FindByIdAsync(userId); foreach (var role in _roleManager.Roles.ToList()) { var userRolesViewModel = new UserRolesViewModel { RoleName = role.Name }; if (await _userManager.IsInRoleAsync(user, role.Name)) { userRolesViewModel.Selected = true; } else { userRolesViewModel.Selected = false; } viewModel.Add(userRolesViewModel); } var model = new ManageUserRolesViewModel() { UserId = userId, UserRoles = viewModel }; return View(model); } public async Task<IActionResult> Update(string id, ManageUserRolesViewModel model) { var user = await _userManager.FindByIdAsync(id); var roles = await _userManager.GetRolesAsync(user); var result = await _userManager.RemoveFromRolesAsync(user, roles); result = await _userManager.AddToRolesAsync(user, model.UserRoles.Where(x => x.Selected).Select(y => y.RoleName)); var currentUser = await _userManager.GetUserAsync(User); await _signInManager.RefreshSignInAsync(currentUser); await Seeds.DefaultUsers.SeedSuperAdminAsync(_userManager, _roleManager); return RedirectToAction("Index", new { userId = id }); } }
Line #13 – #40: Here, we cycle through each of the available roles and check if the selected user is already in the corresponding role. If the user is not in the iterated role, we change the status of the Selected boolean to false. We would go on later in the View to uncheck the roles in list based on this algorithm. Finally, we return the model to the View.
Line #40 – #50: This is another crucial method to update the user-role linkage. To make the entire process cleaner, we first remove all the existing roles from the user. And finally, we re-add the roles which are selected in UI when the user clicks Save.
Line #48: This is just a fallback code in case one admin tries to change the roles of another. You get the point. You are always free to modify these logics as your organization requires.
As usual, let’s create a UI for the User-Role management. This will also be for the Index Action Method.
@model PermissionManagement.MVC.Models.ManageUserRolesViewModel <h3>Manage Roles for @Model.UserId</h3> <br /> <div class="card"> <div id="viewAll" class="card-body table-responsive"> <form asp-controller="userroles" method="post" asp-action="update" asp-route-id="@Model.UserId" class="d-inline"> <input asp-for="@Model.UserId" type="hidden" /> <table class="table table-striped" id="userRolesTable"> <thead> <tr> <th> Role </th> <th> Status </th> </tr> </thead> <tbody> @for (int i = 0; i < Model.UserRoles.Count(); i++) { <tr> <td> <input asp-for="@Model.UserRoles[i].RoleName" type="hidden" /> @Model.UserRoles[i].RoleName </td> <td> <div class="form-check m-1"> <input asp-for="@Model.UserRoles[i].Selected" class="form-check-input" /> </div> </td> </tr> } </tbody> </table> <div class="col-sm-12" style=" padding: 20px 20px 0px 0px"> <button type="submit" id="save" class="btn bg-primary"> <i class="fa fa-check"></i> Save </button> </div> </form> </div> </div>
.NET 5 Clean Architecture – Boilerplate
ASP.NET Core Hero Boilerplate – Clean Architecture Solution Template for ASP.NET Core 5.0. Built with Onion/Hexagonal Architecture and incorporates the most essential Packages your projects will ever need. Includes both WebApi and Web(MVC) Projects. Everything is put into a Nuget Package that will allow you to start generating ASP.NET Core 5.0 Solutions within seconds..
Roles-Permission Management UI
In the previous sections, we learnt how to create a Management UI for User-Roles. Now, let’s create one for Roles-Permissions/Claims. Before that, let’s add a new Model to hold the Permission and Roles Data. We will name it PermissionViewModel.cs. This is almost the same approach that we had used for the previous Management UI.
public class PermissionViewModel { public string RoleId { get; set; } public IList<RoleClaimsViewModel> RoleClaims { get; set; } } public class RoleClaimsViewModel { public string Type { get; set; } public string Value { get; set; } public bool Selected { get; set; } }
After that, let’s add a new Controller, PermissionController.
[Authorize(Roles = "SuperAdmin")] public class PermissionController : Controller { private readonly RoleManager<IdentityRole> _roleManager; public PermissionController(RoleManager<IdentityRole> roleManager) { _roleManager = roleManager; } public async Task<ActionResult> Index(string roleId) { var model = new PermissionViewModel(); var allPermissions = new List<RoleClaimsViewModel>(); allPermissions.GetPermissions(typeof(Permissions.Products), roleId); var role = await _roleManager.FindByIdAsync(roleId); model.RoleId = roleId; var claims = await _roleManager.GetClaimsAsync(role); var allClaimValues = allPermissions.Select(a => a.Value).ToList(); var roleClaimValues = claims.Select(a => a.Value).ToList(); var authorizedClaims = allClaimValues.Intersect(roleClaimValues).ToList(); foreach (var permission in allPermissions) { if (authorizedClaims.Any(a => a == permission.Value)) { permission.Selected = true; } } model.RoleClaims = allPermissions; return View(model); } public async Task<IActionResult> Update(PermissionViewModel model) { var role = await _roleManager.FindByIdAsync(model.RoleId); var claims = await _roleManager.GetClaimsAsync(role); foreach (var claim in claims) { await _roleManager.RemoveClaimAsync(role, claim); } var selectedClaims = model.RoleClaims.Where(a => a.Selected).ToList(); foreach (var claim in selectedClaims) { await _roleManager.AddPermissionClaim(role, claim.Value); } return RedirectToAction("Index", new { roleId = model.RoleId }); } }
Line #10 – #30: The index method returns a list of DTO models that contains the details on which Permissions are active for the corresponding UserRole.
Line #14: Note that we are adding the Product Permissions List to the UI Model. Every time you add a new Entity like Brands / Customer, you will have to add those permissions to the UI this way.
Line #31 – #44: Once the SuperAdmin Maps new Permission to a selected user and click the Save Button, the enabled permissions are added to the Role.
Line #42 & #14: Please note that we will be adding these extension (‘AddPermissionClaim’ and ‘GetPermissions’) later in this tutorial. Do not worry if the reference is not resolved. Just follow along. 😉
Finally, Let’s add a straightforward UI to display the Role-Permissions Mappings and a feature to enable/disable Permissions (only by the superadmin).
@model PermissionManagement.MVC.Models.PermissionViewModel <h1>Permissions</h1> <br /> <div class="card"> <div id="viewAll" class="card-body table-responsive"> <form asp-controller="permission" method="post" asp-action="Update" class="d-inline"> <input asp-for="@Model.RoleId" type="hidden" /> <table class="table table-striped" id="permissionTable"> <thead> <tr> <th> Type </th> <th> Permission </th> <th> Status </th> </tr> </thead> <tbody> @for (int i = 0; i < Model.RoleClaims.Count(); i++) { <tr> <td> <input asp-for="@Model.RoleClaims[i].Type" type="hidden" /> @Model.RoleClaims[i].Type </td> <td> <input asp-for="@Model.RoleClaims[i].Value" type="hidden" /> @Model.RoleClaims[i].Value </td> <td> <div class="form-check m-1"> <input asp-for="@Model.RoleClaims[i].Selected" class="form-check-input" /> </div> </td> </tr> } </tbody> </table> <div class="col-sm-12" style="padding: 20px 20px 0px 0px"> <button type="submit" id="save" class="btn btn-success"> <i class="fa fa-check"></i> Save </button> </div> </form> </div> </div>
Line #23 – #40: A for loop to iterate through the available permissions and set the current status of the permission in relation to the user role.
Claims Helper
As mentioned in the previous section, we have not implemented AddPermissionClaim and GetPermissions yet. Let’s create a new folder, Helpers, and add a new class, ClaimsHelper.cs
public static class ClaimsHelper { public static void GetPermissions(this List<RoleClaimsViewModel> allPermissions, Type policy, string roleId) { FieldInfo[] fields = policy.GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fi in fields) { allPermissions.Add(new RoleClaimsViewModel { Value = fi.GetValue(null).ToString(), Type = "Permissions" }); } } public static async Task AddPermissionClaim(this RoleManager<IdentityRole> roleManager, IdentityRole role, string permission) { var allClaims = await roleManager.GetClaimsAsync(role); if (!allClaims.Any(a => a.Type == "Permission" && a.Value == permission)) { await roleManager.AddClaimAsync(role, new Claim("Permission", permission)); } } }
GetPermissions Extension method takes in a list of available permissions, the type of permission (for instance ProductPermissions) to be added, and Role Id. It then adds all the properties mentioned in the ProductPermissions using Reflection. This is a simple helper class that can be further optimized.
AddPermissionClaim: Remember that we have already used this while seeding permissions for the SuperAdmin Role? I am just duplicating it here for better understanding. Putting the code into words, this extension method is responsible for adding the selected claims from the UI to the user role.
Permission Requirement
Next, Let’s create a class that will essentially help to evaluate permission. Create a New Folder, Permission, and add a new class PermissionRequirement.cs
internal class PermissionRequirement : IAuthorizationRequirement { public string Permission { get; private set; } public PermissionRequirement(string permission) { Permission = permission; } }
Authorization Handler
Second, we need an authorization handler that verifies if a user has the needed permission to access the resource. Create another class and name it PermissionAuthorizationHandler.cs
internal class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement> { public PermissionAuthorizationHandler(){} protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { if (context.User == null) { return; } var permissionss = context.User.Claims.Where(x => x.Type == "Permission" && x.Value == requirement.Permission && x.Issuer == "LOCAL AUTHORITY"); if (permissionss.Any()) { context.Succeed(requirement); return; } } }
Line #10: Gets all the Claims of the User of Type ‘Permission’ and checks if anyone matches the required permission.
Line #13: If there is a match, the user is allowed to access the protected resource. Else, the user will be presented with an Access Denied Page. Pretty Simple yeah?
Permission Policy Provider
This is a smarter way to add policies within the system. As and when the number of permissions keeps on increasing, we do not have to add each of these permissions into our policies. Rather, here is a dynamic way to achieve the same.
Create another class, PermissionPolicyProvider.cs
internal class PermissionPolicyProvider : IAuthorizationPolicyProvider { public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } public PermissionPolicyProvider(IOptions<AuthorizationOptions> options) { FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); } public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync(); public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith("Permission", StringComparison.OrdinalIgnoreCase)) { var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new PermissionRequirement(policyName)); return Task.FromResult(policy.Build()); } return FallbackPolicyProvider.GetPolicyAsync(policyName); } public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync(); }
Line #11 – #16: here is where we dynamically add the incoming permission to the PolicyBuilder.
This method adds the permission to the AuthorizationPolicyBuilder and returns the policy.
Registering the Service
As the final step of the entire process, let’s start registering our services into the ASP.NET Core Container. Open up the Startup.cs/ConfigureServices method and add in the following. Line #3 and #4 are related to the Permission classes we created in the previous sections.
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>(); services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>(); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultUI() .AddDefaultTokenProviders(); services.AddControllersWithViews(); }
Product Controller
Now, as a demonstration, let me create a Product Controller that protects the CRUD Operations and display the features only to the roles it is meant for. Create a new Controller, ProductController. The idea is going to be simple, a view with 4 Buttons namely Create, Read, Edit, Delete. To keep things minimal, we are not going to implement any CRUD operations here. Rather it will be just those buttons to verify that our implementation works.
For an Advanced CRUD Implementation in Razor Pages using jQuery, please refer to this article – Razor Page CRUD in ASP.NET Core with jQuery AJAX – Ultimate Guide
public class ProductController: Controller { public IActionResult Index() { return View(); } }
Next, let’s add a View for the Product’s Index method.
@using Microsoft.AspNetCore.Authorization @inject IAuthorizationService AuthorizationService @using PermissionManagement.MVC.Constants <h1>Product Management</h1> <br /> @if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Create)).Result.Succeeded) { <button class="btn btn-success">Create</button> } @if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.View)).Result.Succeeded) { <button class="btn btn-info">View</button> } @if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Edit)).Result.Succeeded) { <button class="btn btn-warning">Modify</button> } @if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Delete)).Result.Succeeded) { <button class="btn btn-danger">Delete</button> }
Here we will use the IAuthorizationService that comes with ASP.NET Core as part of Authorization. This is quite helpful when you want to control the Authorization at the View level. Yes, you can do a similar task by restricting at the Controller level using the [Authorize(policyName)] decorator, but getting this level of detailed auth control is pretty cool, yeah?
AuthorizationService.AuthorizeAsync(User, Permissions.Products.Edit) – This is an async method that checks if the user role of the current user has the permission to Edit Products. Makes sense?
Let’s run the application now, with SuperAdmin credentials. Navigate to /products. As excepted, the superadmin has access to all the features of the Product module, thanks to seeding. I have showcased the other screenshots earlier in this article in the What we will build? (Screenshots Included) section.

Let’s wrap up the article.
Summary
In this article, we have implemented a complete Permission-Based Authorization in ASP.NET Core using .NET 5 and Microsoft Identity package. We built the entire system from scratch to control the level of authorization on the basis of User Roles. The SuperAdmin will be able to control the permission and add new roles as well. This is a neat way to secure your ASP.NET Core Web Applications from users with limited permissions. You can find the entire source code of the implementation here.
Leave behind your valuable queries, suggestions in the comment section below. Also, if you think that you learned something new from this article, do not forget to share this within your developer community. Happy Coding!
internal class PermissionPolicyProvider : IAuthorizationPolicyProvider
{
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public PermissionPolicyProvider(IOptions options)
{
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();
public Task GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(“Permission”, StringComparison.OrdinalIgnoreCase))
{
var policy = new AuthorizationPolicyBuilder();
policy.AddRequirements(new PermissionRequirement(policyName));
return Task.FromResult(policy.Build());
}
return FallbackPolicyProvider.GetPolicyAsync(policyName);
}
public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();
}
I dont get this code. where did u get this code from?
If I am writing on blazor. How can I achhevie this word
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
@using PermissionManagement.MVC.Constants
Product Management
@if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Create)).Result.Succeeded)
{
Create
}
@if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.View)).Result.Succeeded)
{
View
}
@if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Edit)).Result.Succeeded)
{
Modify
}
@if ((AuthorizationService.AuthorizeAsync(User, Permissions.Products.Delete)).Result.Succeeded)
{
Delete
}
It seemed there is erorr showing User is datatype use as variable.
Hi there
Did you manage this solution with Blazor.
If so could you please show us how to.
Thank you very much for your cooperation.
Hi Tarik, This is already implemented in our new project, Blazor Hero. You can read about it in detail here – https://codewithmukesh.com/blog/blazor-hero-quick-start-guide/
Do not forget to leave your feedback as well 😉
Regards
Thank you very much Mukesh.
آHi Mukesh
Thank you for all your perfect articles.
please tell your idea about below solution for permissions in asp.net core.
https://stackoverflow.com/questions/31464359/how-do-you-create-a-custom-authorizeattribute-in-asp-net-core/31465227#31465227
I’m trying to convert this to Razor pages and for the most part, I’m successful. A few things to note when developing this from scratch.
1) Make sure you add .AddRoles() after your services.AddDefaultIdentity()
2) If doing this by hand (not copy and paste) don’t forget to put host.Run() or await host.RunAsync() at the end of your Main code (doh!)
Thanks for the work!
Hi, Thanks for the knowledge ✌️
Regards
Hi Kent
I’m trying to convert to Razor pages but i’m not successful
you can help me?
Hello Mukesh,
I am a beginner in this domain and found out your admin lte starter kit with .net core 3.1. Now I don’t u understand many things.
1) How to I add custom views using controllers as there is no default controller folder. Do I have to create one? If yes then where.
2) When I install the extension a default db starting with “aspnet” and then some long gibberish is created. I tried adding a table to it and then on using the scaffold command to generate models it generates models for all the tables including the identity ones. Now, how do I use this table to perform CRUD with MVC.
3) Correct me if I’m wrong. I thought this was a .net core project with razor pages but upon reading your quick start it seems that its MVC. So, where do I create the controllere folder?
4) And, if I want to use that template with razor pages what will I have to do ? Please guide.
I really need your help or anyone else who can answer my questions. Really appreciate any kind of help. Thank you!
How can I will generate the permissions dynamically for controllers that will later create ?
hi mukesh
After completing all the steps and making a run for the project, the main page of the site is not displayed until after logging in?
Thank You, Very good explanation.
I have a question:
If I have more than one stock management system with the same users, How can I handle users’ permission?
For example:
User A has to write permission on stock management 1
User A has just view permission on stock management 2
thanks for your nice article, I wish to apply it to my own project but through the controller/action, not a permission class because I have more than 100 actions and models! do u have any suggestion for me?
Is it possible to create a random role and then select if they can for example CRUD production, and just read another, etc? How is this done when you have to “hard code” the role in the authorize attribute on the controller?
I think that you can hardcode the policy, not the role.
Hi Mukesh
After completing all the steps and making a run for the project, how to check by skipping the login step when running the project for the first time ?
please help me
Hi Mukesh!
There is no limit of the number of permissions, I understand that this claims are stored in identity cookie right?
I dont use EntityFramework, ASP identity tables however above projects looks cool, so can we achieve similar with other Dapper with Custom identity tables ? I am trying to find out when exactly it is attaching Role Claim but didn’t got it working…Any input?
can you provide me database file
I am using Code First Approach – EFCore. You don’t need a DB file to make this implementation running. Just use the EF Tool commands to generate the database.
Regards
Run the following command in the Package Manager Console (PMC):
PM> Update-Database
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&tabs=visual-studio#apply-migrations
What happen when try to consult a Permission that don´t start whith Permission.model.action prefix what return to the view?
Hi Mukesh, Thanks for this clear demo.
in a normal project, we have more than one entity. you explain in this example using product entity. what should I do to apply this concept on more than one entity? should I repeat this code snippet for every entity?
public static List GeneratePermissionsForModule(string module)
{
return new List()
{
$”Permissions.{module}.Create”,
$”Permissions.{module}.View”,
$”Permissions.{module}.Edit”,
$”Permissions.{module}.Delete”,
};
}
public static class Products
{
public const string View = “Permissions.Products.View”;
public const string Create = “Permissions.Products.Create”;
public const string Edit = “Permissions.Products.Edit”;
public const string Delete = “Permissions.Products.Delete”;
}
Update GetPermissions method that it loops through each Property
public static void GetPermissions(this List allPermissions, string roleId)
{
var fields = new List();
foreach (var p in typeof(Constants.Permissions).GetNestedTypes())
{
fields.AddRange(p.GetFields(BindingFlags.Static | BindingFlags.Public).ToList());
}
foreach (FieldInfo fi in fields)
{
allPermissions.Add(new RoleClaimsViewModel { Value = fi.GetValue(null).ToString(), Type = “Permissions” });
}
}
yes i have the same question did you find the solution??
Hi Mukesh, Thanks for you.
in a normal project, we have more than one entity. you explain in this example using product entity. what should I do to apply this concept on more than one entity?
Hi Mukesh. Thanks for sharing your knowledge.
I am having an error in the UserRolesController:
An unhandled exception occurred while processing the request.
InvalidOperationException: There is already an open DataReader
associated with this Connection which must be closed first.
i’ve checked all , and didnt’n find a solution. Here is the code of this block:
public async Task Index(string userId)
{
var viewModel = new List();
var user = await _userManager.FindByIdAsync(userId);
foreach (var role in _roleManager.Roles)
{
var userRolesViewModel = new UserRolesViewModel
{
RoleName = role.Name
};
if (await _userManager.IsInRoleAsync(user, role.Name))
{
userRolesViewModel.Selected = true;
}
else
{
userRolesViewModel.Selected = false;
}
viewModel.Add(userRolesViewModel);
}
var model = new ManageUserRolesViewModel()
{
UserId = userId,
UserRoles = viewModel
};
return View(model);
}
……..thanks any help.
Hi,
in the code block you sent, can you change foreach (var role in _roleManager.Roles) to foreach (var role in _roleManager.Roles.ToList())
That should probably fix the issue you have. Do let me know! Thanks
Enable MARS
https://www.connectionstrings.com/microsoft-data-sqlclient/enable-mars/
Hi
My site has large number of permission , say 100 modules and each modules has View, Create,Edit,Delete permission.
So total claim will be 400. i.e 400 rows in [AspNetRoleClaims]
When I have large permissions, Cookie length exceed to max supported size by the browser. In this case, it will throw.HTTP Error 400. The size of the request headers is too long.
Is there any way we can fix this issue when using claim based authorization?
When a role has about 200+ claim permission, such user get those error (“Cookie length exceed …”)
Use JWT Authentication
I have the same issue:
Htttp 400 Bad Request Request Header is too long
https://stackoverflow.com/questions/67280411/htttp-400-bad-request-request-header-is-too-long
I am fixing this problem by creating permissions table and using db not claims.
The infrastructure of this project is good, but mechanism of storing claims in cookies is bad.
Great Tutorial.
After following it within my project, I have an issue where it looks like there is a recursion when the code redirects to login; the requested url ends up being (below).
If I comment out the policy startup, I receive the login page and it works fine – once logged in, everything is good (even if I add the policy startup back in) until the user is logged out. I’ve set breakpoints, I don’t see where any of the policy code is called during this – so I am at somewhat of a loss as to how to troubleshoot this? Any ideas?
— Below is the generated login url, you can see the information repeated over and over again inside the url. —
https://localhost:44391/Account/Login?ReturnUrl=%2FAccount%2FLogin%3FReturnUrl%3D%252FAccount%252FLogin%253FReturnUrl%253D%25252FAccount%25252FLogin%25253FReturnUrl%25253D%2525252FAccount%2525252FLogin%2525253FReturnUrl%2525253D%252525252FAccount%252525252FLogin%252525253FReturnUrl%252525253D%25252525252FAccount%25252525252FLogin%25252525253FReturnUrl%25252525253D%2525252525252FAccount%2525252525252FLogin%2525252525253FReturnUrl%2525252525253D%252525252525252FAccount%252525252525252FLogin%252525252525253FReturnUrl%252525252525253D%25252525252525252FAccount%25252525252525252FLogin%25252525252525253FReturnUrl%25252525252525253D%2525252525252525252FAccount%2525252525252525252FLogin%2525252525252525253FReturnUrl%2525252525252525253D%252525252525252525252FAccount%252525252525252525252FLogin%252525252525252525253FReturnUrl%252525252525252525253D%25252525252525252525252FAccount%25252525252525252525252FLogin%25252525252525252525253FReturnUrl%25252525252525252525253D%2525252525252525252525252FAccount%2525252525252525252525252FLogin%2525252525252525252525253FReturnUrl%2525252525252525252525253D%252525252525252525252525252FAccount%252525252525252525252525252FLogin%252525252525252525252525253FReturnUrl%252525252525252525252525253D%25252525252525252525252525252FAccount%25252525252525252525252525252FLogin%25252525252525252525252525253FReturnUrl%25252525252525252525252525253D%2525252525252525252525252525252FAccount%2525252525252525252525252525252FLogin%2525252525252525252525252525253FReturnUrl%2525252525252525252525252525253D%252525252525252525252525252525252FAccount%252525252525252525252525252525252FLogin%252525252525252525252525252525253FReturnUrl%252525252525252525252525252525253D%25252525252525252525252525252525252FAccount%25252525252525252525252525252525252FLogin%25252525252525252525252525252525253FReturnUrl%25252525252525252525252525252525253D%2525252525252525252525252525252525252FAccount%2525252525252525252525252525252525252FLogin%2525252525252525252525252525252525253FReturnUrl%2525252525252525252525252525252525253D%252525252525252525252525252525252525252FAccount%252525252525252525252525252525252525252FLogin%252525252525252525252525252525252525253FReturnUrl%252525252525252525252525252525252525253D%25252525252525252525252525252525252525252F
I see the code call this over and over inside PermissionPolicyProvider.
public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();
The default is indicating that everything is denied for some reason.
For other’s benefits, I am not 100% sure this is correct, however changing the PermissionPolicyProvider’s GetFallbackPolicyAsync method to this seems to at least helped the issue as far as not being able to log in.
public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync(); // .GetDefaultPolicyAsync();
I’m interested in what others think about this change.
I am also not sure what the correct way to do it would be, but as you point out the way it was written in the example it denies everything by default (that is not marked as [AllowAnonymous]).
My problem was not with Login (as I had it marked with [AllowAnonymous]), but my problem was that in order to see the error pages (404 not found etc.) via UseStatusCodePages you had to be Logged-in.
Your solution seams to work and I hope it is the right way to do it, and hopefully someone can comment and confirm your solution is the correct one.
For the search engines: IAuthorizationPolicyProvider AllowAnonymous not working when using this in Razor Pages. Since you cannot tag a handler method with AllowAnonymous you can’t use the Authorize attribute on the class and the AllowAnonymous attribute on the method.
Changing this:
public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();
to this:
public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync();
Fixes the issue and allows classes to be tagged with [AllowAnonymous]
Hi Mukesh.
Thanks for your guide.
I have tried to implementation as your guide.
I have problem at the rolecontroller the code has been upload to
https://github.com/nguyentuananh921/Betting.git
In the rolecontroller.cs
I have the action:
public async Task Index()
{
var roles = await _roleManager.Roles.ToListAsync();
return View(roles);
}
And in the Index view I have done as you guide.
//Start from here
@model List
@{
ViewData[“Title”] = “Role Manager”;
Layout = “~/Views/Shared/_Layout.cshtml”;
}
Role Manager
Add New Role
//—– remove to clear.
The problem is when I click on the button the action does not rout to AddRole of the RoleController.
Everything will work file if I add the row
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
at the top of the index.cshtml.
I Still confuse about why i have to add this row at each view when I have added it in the _ViewImports.cshtml
Thanks for your guide and hoping to see you support.
Thank you Mukesh for the amazing tutorial!
There is a serious question, which already been asked by (@Jorge Curiel and @Dilli Shrestha) regarding the Cookie size limit which affects the number of permissions that can be added using this approach.
Please help us with an alternative approach to accomplish the same task.
Hi,
I would suggest altering the permission checking strategy a bit. In cases where there are 50+ permissions involved, storing in the cookie would probably give you a ‘Header too long’ Bad Request status code. In this scenario, it’s better to implement a real-time permission checking mechanism rather than storing it in the cookie. Ideally, you would need to remove the permission added to the cookie and have an API endpoint that verifies the request for permissions using the current user role ID.
Regards
Hi, I’m using azure AD to Authorize user. But I want to add and manage user’s role in my database not using azure AD roles. How can I do this
Hi,
Good tutorial, im a novice with this but seem to have an issue with the below
public async Task Update(PermissionViewModel model)
{
var role = await _roleManager.FindByIdAsync(model.RoleId);
var claims = await _roleManager.GetClaimsAsync(role);
foreach (var claim in claims)
{
await _roleManager.RemoveClaimAsync(role, claim);
}
var selectedClaims = model.RoleClaims.Where(a => a.Selected).ToList();
foreach (var claim in selectedClaims)
{
await _roleManager.AddPermissionClaim(role, claim.Value);
}
return RedirectToAction(“Index”, new { roleId = model.RoleId });
}
speciffically this line
await _roleManager.AddPermissionClaim(role, claim.Value);
throws a CS0121 error.
I have used a newer dot net. visual studio 2022
do you know of a quick fix, or would i be better redoing this in the same dotnet. ?
thanks
Paul
Hi Sir,
Sir how can I login or registered as a super admin here when I run the code?
Appreciated You Work!
Hey there,
First, great article! I followed your example code to write my own app. Get everything going but whatever default user I tried login failed with “Invalid Login”; the user data was never written to the db by the seeding methods. I failed to find this for several hours until I realized, I changed the default passwords to lowercase in my code – user manager CreateAsync fails if you don’t add an upper case character to the password, (by default).
Thanks for your hard work!
Hi, How can I implement the Authorization Handler method in my code, I am trying to use it in an Api project. So I am confused as to where to call it in order to proceed.
Regards.
Hi Mukesh, thanks a lot for this tutorial, it was very usefull for me.
I only have one question:
I am in two differents browser, one with superAdmin role and other with basic role.
If I change permissions using superAdmin role, I need to logout/login to updates new permissions;
How can I change this and system always query in database for permissions?
Thanks for your help.
Thanks it really helped
Hi there,
I’m trying to adapt this for a Asp.Net Core Web API.
Most of it seems to work, I’m just having trouble with the `AuthorizeAsync` call.
On the authorization service, there is no signature that allow me to just pass a User+permission(as string). I’m directly expected to provide an `AuthorizationPolicy` here. Should I inject myself the `IAuthorizationPolicyProvider`, build the `AuthorizationPolicy` and provide to the `AuthorizeAsync` method, or am I missing something?
Thanks
Hello,
This code have error when we create many permissions.
Request too long.
Hi man
First of all, great content!
Could you please show how can i change default user id wich is string into int?
Great article and it was very helpful for me, Thanks so much!!
Great, I learned a lot, before that I did not know what, there is such a thing as permission exists
Excellent Article…Thank you Mukesh…
I like this website so much, saved to bookmarks. “To hold a pen is to be at war.” by Francois Marie Arouet Voltaire.
Thanks a lot, very helpful.
Hi Mukesh , Thanks for this wonderful Article. I have implemented the same in my web application. its works perfect.
Can you please tell me how can I expend it for more then one entity so that user can select module name and Manage its permission accordingly.
Regards
Hi I have find some code to extend its functionality. Hope somebody else help it.
Modify claimsHelper.cs with this peace of code to get the complete list of classes :-
foreach (var fi in typeof(Permissions).GetNestedTypes().SelectMany(c => c.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)))
{
allPermissions.Add(new RoleClaimsViewModel { Value = fi.GetValue(null).ToString(), Type = “Permissions” });
}
Thank you very much for all of your articles Mr. Mukesh!
your articles are very helpfull for beginers and intermediate developers.