Asp.Net Core -Authorizationz授权

授权的内部实现参考

动态授权参考

 

动态授权

基于权限的授权

1.定义权限-Permissions

 public class Permissions
 {
     public const string Admin = "Admin";
     public const string Users = "Users";
     public const string UserCreate = Users+ ".Create";
     public const string UserUpdate = Users+ ".Update";
     public const string UserDelete = Users+ ".Delete";
 }

 

2.定义权限Requirement

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    //表示权限的名称与Permission中常量对应
    public string Name { get; set; }
    public PermissionAuthorizationRequirement(string name)
    {
        Name = name;
    }
}

 

3.自定义授权Handler

public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
    {
        //判断用户是否有某个角色
        if (context.User.IsInRole(Permissions.Admin))
        {
           context.Succeed(requirement);
        }
        else
        {
            //取出登录用户中ClaimType为Permission的项取出,并获取其 Value 组成一个 List<string>
            //var permissions = context.User.Claims.Where(p => p.Type == "Permissions").Select(p => p.Value).ToList();
            var permissions = context.User.Claims.Where(p => p.Type == nameof(Permissions)).Select(p => p.Value).ToList();
            //验证requirement是否满足授权(验证用户权限中是否存在requirement<请求中需要的权限>中的权限)
            if (permissions.Any(p => p.StartsWith(requirement.Name)))
            {
                //表示将验证成功的requirement从待验证的Requirements中移除(具体内容查看AuthorizationHandlerContext源码)
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}

 

4.注册Handler

在Program中注册

builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();

 

5.根据定义的权限添加权限策略

手动添加权限策略

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(Permissions.Users, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.Users)));
    options.AddPolicy(Permissions.UserCreate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserCreate)));
    options.AddPolicy(Permissions.UserUpdate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserUpdate)));
    options.AddPolicy(Permissions.UserDelete, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserDelete)));
});

 自动添加权限策略(根据特性[Authorize]加入的权限动态添加)

 /// <summary>
 /// 动态添加policy---自定义的 AuthorizationPolicyProvider 必须实现 IAuthorizationPolicyProvider,否则添加到 DI 时会不生效
 /// 访问接口时需要用到权限就依次动态加载进来成为一项policy,由多少个权限就生成多少个policy,并且每一个policy都会按顺序执行一次
 /// PermissionAuthorizationHandler的HandleRequirementAsync方法
 /// </summary>
 public class PermissionAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider, IAuthorizationPolicyProvider
 {
     public PermissionAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : base(options) { }

     //返回默认授权策略(在未指定策略的情况下用于 [Authorize] 属性的策略)
     public new Task<AuthorizationPolicy> GetDefaultPolicyAsync() => base.GetDefaultPolicyAsync();
     //返回回退授权策略(在未指定策略时由授权中间件使用的策略)
     public new Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => base.GetFallbackPolicyAsync();
     //返回指定名称的授权策略
     public new Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
     {
         if (policyName.StartsWith(Permissions.Users))
         {
             var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme);
             policy.AddRequirements(new PermissionAuthorizationRequirement(policyName));
             return Task.FromResult<AuthorizationPolicy?>(policy.Build());
         }
         return base.GetPolicyAsync(policyName);
     }
 }

将PermissionAuthorizationPolicyProvider进行DI注入

builder.Services.AddSingleton<IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>();

 

6.使用授权策略

 以上方式需要对每个策略去做添加过于繁琐,可以通过MVC过滤器调用IAuthorizationService来简化操作

 

7.自定义过滤器-PermissionAuthorizeAttribute

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple =true,Inherited =true)]
public class PermissionAuthorizeAttribute : Attribute, IAsyncAuthorizationFilter
{
    public string Name { get; set; }
    public PermissionAuthorizeAttribute(string name)
    {
        Name = name;
    }
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
       var authorizationService=context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
        //调用AuthorizeAsync方法
        var authorizationResult = await authorizationService.AuthorizeAsync(context.HttpContext.User, null, new PermissionAuthorizationRequirement(Name));
        if (!authorizationResult.Succeeded)
        {
            context.Result = new ForbidResult();
        }
    }
}

使用授权策略改为

 ASP.NET Core 中内置了一些常用授权策略实现

  • AssertionRequirement :使用最原始的断言形式来声明授权策略。
  • DenyAnonymousAuthorizationRequirement :用于表示禁止匿名用户访问的授权策略,并在AuthorizationOptions中将其设置为默认策略。
  • ClaimsAuthorizationRequirement :用于表示判断Cliams中是否包含预期的Claims的授权策略。
  • RolesAuthorizationRequirement :用于表示使用ClaimsPrincipal.IsInRole来判断是否包含预期的Role的授权策略。
  • NameAuthorizationRequirement:用于表示使用ClaimsPrincipal.Identities.Name来判断是否包含预期的Name的授权策略。
  • OperationAuthorizationRequirement:用于表示基于操作的授权策略。

 

授权回退策略

 应用于未显式指定授权策略的所有请求。 对于终结点路由提供的请求,这包括未指定授权属性的任何终结点。 对于在授权中间件之后由其他中间件提供的请求(如静态文件),这会将策略应用于所有请求。

builder.Services.AddAuthorization(options =>
{
    //具有授权属性的 Razor Pages、控制器或操作方法除外不受回退授权策略的影响,例如含有授权属性[AllowAnonymous] [Authorize]等的不受回退策略影响
    //回退策略 回退授权策略要求所有用户进行身份验证
    options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();//回退策略要求所有用户进行身份验证
});

 

posted @ 2024-07-03 16:28  流年sugar  阅读(49)  评论(0编辑  收藏  举报