如何在ASP.net核心身份中实现基于权限的授权?

时间:2018-12-30 11:53:30

标签: c# asp.net-web-api asp.net-core asp.net-identity

我正在尝试使用asp.net Identity Core保护我的webAPI。现在,我想动态创建角色,并在我的管理面板中为其设置权限和从中删除权限。

例如,我有此权限列表:

  • 注册任务
  • 分配任务
  • 更改任务状态
  • 验证任务状态

现在我想创建不同的角色,并根据需要设置对这些角色的权限,并将这些角色分配给每个用户。

我在Identity框架的UserManager和RoleManager中进行了搜索,但是无法创建此功能。

有没有实现此功能的方法? 我发现this有用,但这是关于dotnet

2 个答案:

答案 0 :(得分:2)

我发现在this链接中使用声明和策略创建基于权限的授权的方法。

我创建一个自定义声明类型,例如 Application.Permission ,然后创建一些如下的类来定义我的权限:

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";
} 

然后创建我的角色,然后使用键 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));

下一步,当用户尝试登录系统时,我会将这些声明添加到我的令牌中:

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);

然后我以这种方式创建我的政策:

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

然后我在ConfigureServiceSection的 startup.cs 文件中设置授权服务:

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); });
}

最后,我在路线上设置了策略并完成:

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

答案 1 :(得分:1)

另一种解决方案可能是使用func来填充策略,请参见此示例取自https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1

services.AddAuthorization(options =>
{
     options.AddPolicy("BadgeEntry", policy =>
        policy.RequireAssertion(context =>
            context.User.HasClaim(c =>
                (c.Type == "BadgeId" ||
                 c.Type == "TemporaryBadgeId") &&
                 c.Issuer == "https://microsoftsecurity")));
});

考虑到这一点,您可以进行如下操作。

首先是一个针对您所有个人权限的课程:

public static class PrincipalPermission{

       public static List<Func<AuthorizationHandlerContext, bool>> Criteria = new List<Func<AuthorizationHandlerContext, bool>>
        {
            CanCreateUser
        };

        public static bool CanCreateUser(this AuthorizationHandlerContext ctx)
        {
            return ctx.User.IsInRole(RoleEnum.Admin.ToString());
        }
}

然后应将其添加到您的配置中:

services.AddAuthorization(options =>
{

    foreach (var criterion in PrincipalPermissions.Criteria)
            {
                options.AddPolicy(criterion.Method.Name, 
                                  policy => policy.RequireAssertion(criterion));
            }  
}

现在可以将其添加到您的控制器中了

    [Authorize(Policy = nameof(PrincipalPermissions.CanCreateUser))]
    public async Task<UserDto> Create([FromBody] CreateUserCommand cmd)
    {
       return await HandleCreateUser(cmd);
    }

顺便说一句,如果有人认为将方法添加到Criteria列表中很烦人,我就在那里,如果有人能提出更好的解决方案,我将不胜感激:)