Search code examples
c#asp.net-web-apiasp.net-coreasp.net-identity

How to implement permission based authorization in ASP.net core Identity?


I am trying to secure my webAPI using asp.net Identity Core. Now I want to create Roles Dynamically and set and remove permission from/to them and in my admin panel.

for example, I have this permissions list:

  • register task
  • assign task
  • change task status
  • verify task status

now I want to create different roles and set this permission to them as my needs and assign these roles to each user.

I searched in UserManager and RoleManager of Identity framework but there was no way to create this functionality.

is there any method for implementing this functionality? I find this useful but this is about dotnet


Solution

  • I find an approach which is using claim and policy for creating a permission-based authorization in this link.

    I create a custom claim type such as Application.Permission and then create some classes as following to define my permissions:

    public class CustomClaimTypes
    {
        public const string Permission = "Application.Permission";
    }
    
    public static class UserPermissions
    {
        public const string Add = "users.add";
        public const string Edit = "users.edit";
        public const string EditRole = "users.edit.role";
    } 
    

    and then I create My roles and then Assign these permissions as claims to the roles with key ApplicationPermission.

    await roleManager.CreateAsync(new ApplicationRole("User"));
    var userRole = await roleManager.FindByNameAsync("User");
    await roleManager.AddClaimAsync(userRole, new Claim(CustomClaimTypes.Permission, Permissions.User.View));    
    await roleManager.AddClaimAsync(userRole, new Claim(CustomClaimTypes.Permission, Permissions.Team.View));
    

    in the next step, I add these claims to my token when the user is trying to login to system:

    var roles = await _userManager.GetRolesAsync(user);
    var userRoles = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToArray();
    var userClaims = await _userManager.GetClaimsAsync(user).ConfigureAwait(false);
    var roleClaims = await GetRoleClaimsAsync(roles).ConfigureAwait(false);
    var claims = new[]
                 {
                     new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                     new Claim(ClaimTypes.Email, user.Email),
                     new Claim(ClaimTypes.Name, user.UserName)
                 }.Union(userClaims).Union(roleClaims).Union(userRoles);
    
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SigningKey));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
    var token = new JwtSecurityToken(
        issuer: _jwtSettings.Issuer,
        audience: _jwtSettings.Audience,
        claims: claims,
        expires: DateTime.UtcNow.AddYears(1),
        signingCredentials: creds);
    

    then I create my policies this way:

    public static class PolicyTypes
    {
        public static class Users
        {
            public const string Manage = "users.manage.policy";
            public const string EditRole = "users.edit.role.policy";
        }
    }
    

    then I set up my authorization service inside startup.cs file in ConfigureServiceSection:

    services.AddAuthorization(options =>
    {
        options.AddPolicy(PolicyTypes.Users.Manage, policy => { policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Users.Add); });
        options.AddPolicy(PolicyTypes.Users.EditRole, policy => { policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Users.EditRole); });
    }
    

    finally, I set policies on my routes and finish:

    [Authorize(Policy = PolicyTypes.Users.Manage)]
    public async Task<IEnumerable<TeamDto>> GetSubTeams(int parentId)
    {
        var teams = await _teamService.GetSubTeamsAsync(parentId);
        return teams;
    }