.net core 自定义授权策略提供程序进行权限验证
.net core 自定义授权策略提供程序进行权限验证
在这之前先了解一下鉴权和授权的概念;
鉴权
鉴权可以说是身份验证,身份验证是确定用户身份的过程;
在ASP.NET Core 中身份验证是由身份验证服务IAuthenticationService负责的,它被身份验证中间件使用, 身份验证服务会使用已注册的身份验证处理程序来完成与身份验证相关的操作。身份验证相关的操作包括:对用户身份进行验证,对未经身份验证的用户进行资源访问时做出响应。
身份验证处理程序及其配置选项
身份验证处理程序包括CookieAuthenticationHandler 和 JwtBearerHandler,身份验证处理程序的注册 是在调用AddAuthentication之后扩展方法AddJwtBearer 和 AddCookie 提供的
身份验证处理程序会由实现IAuthenticationService 接口的AuthenticationService 的AuthenticateAsync 方法去调用
授权
授权是确定用户是否有权访问资源的过程,这里先简单带过一下后面接着讲
授权方案
授权方案包括 基于角色的授权,基于声明的授权,基于策略的授权,这里着重说一下策略授权,
基于策略的授权
授权策略包含一个或多个要求
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
在前面的示例中,创建了“AtLeast21”策略。 该策略有一个最低年龄要求,其作为要求的参数提供
IAuthorizationRequirement
IAuthorizationRequirement用于跟踪授权是否成功的机制
在IAuthorizationHandler 的 HandleAsync方法中 作为参数被调用,由HttpContext 的Requirements 属性提供
IAuthorizationHandler
IAuthorizationHandler 用于检查策略是否满足要求,主要执行的方法是HandleAsync,我们可以继承微软提供的AuthorizationHandler,默认实现了HandlAsync ,在具有多个IAuthorizationRequirement 的情况下默认是循环去执行HandleRequirementAsync方法,在某些情况下我们可以去重写从而去执行特定IAuthorizationRequirement,当然方法多样
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
if (context.Resource is TResource)
{
foreach (var req in context.Requirements.OfType<TRequirement>())
{
await HandleRequirementAsync(context, req, (TResource)context.Resource);
}
}
}
IAuthorizationPolicyProvider
IAuthorizationPolicyProvider 自定义策略提供程序
继承IAuthorizationPolicyProvider 需要去实现IAuthorizationPolicyProvider 三个方法,三个方法的执行由我们我们的Authorize特性决定,并且Authorize特性的策略名称会传递到 IAuthorizationPolicyProvider 的GetPolicyAsync 作为参数使用
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
var policy = new AuthorizationPolicyBuilder();
//添加鉴权方案
policy.AddAuthenticationSchemes("Bearer");
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
if (policyName is null)
{
return Task.FromResult<AuthorizationPolicy>(null);
}
var authorizations = policyName.Split(',');
if (authorizations.Any())
{
//权限策略构建器,添加自定义的AuthorizaRequirement
policy.AddRequirements(new AuthorizeRequirement(authorizations));
}
return Task.FromResult(policy.Build());
}
这里看一下Authorize特性相关的属性
public class AuthorizeAttribute : Attribute, IAuthorizeData
{
/// <summary>
/// </summary>
public AuthorizeAttribute() { }
/// <summary>
/// 初始化类类实例并且设置可访问资源策略名称
/// </summary>
/// <param name="policy">The name of the policy to require for authorization.</param>
public AuthorizeAttribute(string policy)
{
Policy = policy;
}
/// <summary>
/// 设置或获取可以访问资源策略名称
/// </summary>
public string? Policy { get; set; }
/// <summary>
/// 设置或获取可以访问资源的角色
/// </summary>
public string? Roles { get; set; }
/// <summary>
/// 设置或获取可以访问资源鉴权方案名称
/// </summary>
public string? AuthenticationSchemes { get; set; }
}
GetDefaultPolicyAsync
默认策略,当我们的Authorize特性上不提供策略时执行,这里的CustomAuthorization特性是继承了Authorize特性
[CustomAuthorization]
[HttpGet("SetNotOP")]
[NoResult]
public int SetNotOP()
{
throw new ArgumentNullException(nameof(TestTask));
return 1;
}
GetPolicyAsync
在Authorize添加策略时执行
[CustomAuthorization("test1", "test1")]
[HttpGet("TestTask")]
public async Task<int> TestTask()
{
await Task.CompletedTask;
return 1;
}
GetFallbackPolicyAsync
后备授权策略,是指在没有为请求指定其他策略时,由授权中间件提供的策略。在这里可以指返回空值,也可以设置指定策略返回
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(null);
}
//或者
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
{
var policy = new AuthorizationPolicyBuilder();
policy.AddAuthenticationSchemes("Bearer");
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
return Task.FromResult<AuthorizationPolicy>(policy.Build());
}
IAuthorizationService
IAuthorizationService是确认授权成功与否的主要服务,兵器 负责去执行我们自定义的AuthorizationHandle
看一段由微软官方简化授权服务的代码,可以看到AuthorizeAsync会去循环执行自定义的AuthorizationHandle
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
// Create a tracking context from the authorization inputs.
var authContext = _contextFactory.CreateContext(requirements, user, resource);
// By default this returns an IEnumerable<IAuthorizationHandlers> from DI.
var handlers = await _handlers.GetHandlersAsync(authContext);
// Invoke all handlers.
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
}
// Check the context, by default success is when all requirements have been met.
return _evaluator.Evaluate(authContext);
}
到这里应该对整个授权流程有了个大致的了解,在授权前会由鉴权中间件进行一个鉴权,鉴权通过后由IAuthorizationPolicyProvider 来提供一个授权策略(授权策略里可以添加我们需要的IAuthorizationRequirement),最后由IAuthorizationService 的HandleAsync去执行自定义AuthorizeHandle
具体实现
自定义特性
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public virtual string[] AuthorizeName { get; private set; }
public CustomAuthorizationAttribute(params string[] authorizeName)
{
AuthorizeName = authorizeName;
Policy = string.Join(",", AuthorizeName);
}
}
自定义策略提供程序
public class AuthorizationProvider : IAuthorizationPolicyProvider
{
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
var policy = new AuthorizationPolicyBuilder();
policy.AddAuthenticationSchemes("Bearer");
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
//默认授权测率必须添加一个IAuthorizationRequirement的实现
policy.AddRequirements(new AuthorizeRequirement());
return Task.FromResult<AuthorizationPolicy>(policy.Build());
}
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(null);
}
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
var policy = new AuthorizationPolicyBuilder();
policy.AddAuthenticationSchemes("Bearer");
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
if (policyName is null)
{
return Task.FromResult<AuthorizationPolicy>(null);
}
var authorizations = policyName.Split(',');
if (authorizations.Any())
{
policy.AddRequirements(new AuthorizeRequirement(authorizations));
}
return Task.FromResult(policy.Build());
}
}
自定义授权处理程序
IPermissionsCheck 是我注入的权限检测程序,其实对于权限认证,重要的是控制对资源的访问,整篇文章下来无非就是将特性上的值提供到我们所需要进行权限检测的程序中去,当然我们也可以用权限过滤器反射获取Authorize特性上的值来实现
public class AuthorizeHandler : AuthorizationHandler<AuthorizeRequirement>
{
private readonly IPermissionCheck _permisscheck;
private readonly IHttpContextAccessor _httpContextAccessor;
public AuthorizeHandler(IHttpContextAccessor httpContextAccessor
, IServiceProvider serviceProvider)
{
using var scope = serviceProvider.CreateScope();
_permisscheck = scope.ServiceProvider.GetRequiredService<IPermissionCheck>();
_httpContextAccessor = httpContextAccessor;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizeRequirement requirement)
{
var identity = _httpContextAccessor?.HttpContext?.User?.Identity;
var httpContext = _httpContextAccessor?.HttpContext;
var isAuthenticated = identity?.IsAuthenticated ?? false;
var claims = _httpContextAccessor?.HttpContext?.User?.Claims;
var userId = claims?.FirstOrDefault(p => p.Type == "Id")?.Value;
//判断是否通过鉴权中间件--是否登录
if (userId is null || !isAuthenticated)
{
context.Fail();
return;
}
var defaultPolicy = requirement.AuthorizeName?.Any() ?? false;
//默认授权策略
if (!defaultPolicy)
{
context.Succeed(requirement);
return;
}
var roleIds = claims?
.Where(p => p?.Type?.Equals("RoleIds") ?? false)
.Select(p => long.Parse(p.Value));
var roleNames = claims?
.Where(p => p?.Type?.Equals(ClaimTypes.Role) ?? false)
.Select(p => p.Value);
UserTokenModel tokenModel = new UserTokenModel()
{
UserId = long.Parse(userId ?? "0"),
UserName = claims?.FirstOrDefault(p => p.Type == ClaimTypes.Name)?.Value ?? "",
RoleNames = roleNames?.ToArray(),
RoleIds = roleIds?.ToArray(),
};
if (requirement.AuthorizeName.Any())
{
if (!_permisscheck.IsGranted(tokenModel, requirement.AuthorizeName))
{
context.Fail();
return;
}
}
context.Succeed(requirement);
}
}
自定义IAuthorizationRequirement
public class AuthorizeRequirement : IAuthorizationRequirement
{
public virtual string[] AuthorizeName { get; private set; }
public AuthorizeRequirement(params string[] authorizeName)
{
AuthorizeName = authorizeName;
}
public AuthorizeRequirement() { }
}
自定义授权结果中间件
自定义授权结果中间件的作用,返回自定义响应,增强默认质询或禁止响应
public class AuthorizeMiddleHandle : IAuthorizationMiddlewareResultHandler
{
public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
{
if (!authorizeResult.Succeeded || authorizeResult.Challenged)
{
var isLogin = context?.User?.Identity?.IsAuthenticated ?? false;
var path = context?.Request?.Path ?? "";
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
var response = new AjaxResponse();
response.UnAuthorizedRequest = true;
response.StatusCode = "401";
var error = new ErrorInfo();
error.Error = isLogin ? $"你没有权限访问该接口-接口路由{path}" : "请先登录系统";
response.Error = error;
await context.Response.WriteAsJsonAsync(response);
return;
}
await next(context);
}
}
到这里对于权限认证有了个大概的了解,至于是通过自定义策略提供程序自定义AuthorizHandle这一系列复杂的操作还是通过权限过滤器取决看官自己。个人认为通过自定义策略提供程序自定义AuthorizHandle这种方式更灵活性,能够应对更多复杂场景。
.net core 自定义授权策略提供程序进行权限验证的更多相关文章
- ASP.NET Core 使用外部登陆提供程序登陆的流程,以及身份认证的流程 (转载)
阅读目录 在Asp.Net Core 中使用外部登陆(google.微博...) 中间件管道 The Authentication Middleware The Challenge 与认证中间件进行交 ...
- Net Core 使用外部登陆提供程序登陆的流程,以及身份认证的流程
在Asp.Net Core 中使用外部登陆(google.微博...) 原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET C ...
- 扒一扒.NET Core的环境配置提供程序
很久之前,在玩Docker的时候顺便扒了扒,最近,终于下定决心花了些时间整理并成文,希望能够给大家一些帮助. 目录 .NET Core中的配置 ASP.NET Core中的配置 扒一扒环境变量提供程序 ...
- 【WCF安全】WCF 自定义授权[用户名+密码+x509证书]
1.x509证书制作(略) 2.直接贴代码 ----------------------------------------------------------------------服务端----- ...
- 【WCF】授权策略详解
所谓授权者,就是服务授予客户端是否具有调用某个服务操作的权限. 授权过程可以通过一系列授权策略来进行评估,即每个特定的授权策略都按照各自的需求,衡量一下调用方是否具备访问服务操作的权限.在默认情况下, ...
- SimpleMembership,成员资格提供程序、 通用的提供者和新的 ASP.NET 4.5 Web 窗体和 ASP.NET MVC 4 模板
ASP.NET MVC 4 互联网模板中添加一些新的. 非常有用的功能,构建 SimpleMembership.这些更改将添加一些很有特色,像很多更简单. 可扩展会员 API 和 OAuth 的支持. ...
- ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露
一.前言 在涉及到后端项目的开发中,如何实现对于用户权限的管控是需要我们首先考虑的,在实际开发过程中,我们可能会运用一些已经成熟的解决方案帮助我们实现这一功能,而在 Grapefruit.VuCore ...
- Asp.net Core, 基于 claims 实现权限验证 - 引导篇
什么是Claims? 这个直接阅读其他大神些的文章吧,解释得更好. 相关文章阅读: http://www.cnblogs.com/JustRun1983/p/4708176.html http://w ...
- ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口
目录 ① 存储角色/用户所能访问的 API ② 实现 IAuthorizationRequirement 接口 ③ 实现 TokenValidationParameters ④ 生成 Token ⑤ ...
- gRPC asp.net core自定义策略认证
在GitHub上有个项目,本来是作为自己研究学习.net core的Demo,没想到很多同学在看,还给了很多星,所以觉得应该升成3.0,整理一下,写成博分享给学习.net core的同学们. 项目名称 ...
随机推荐
- linux相关命令-linux查看头两行、查看最后两行-查找一个文件里包含的error信息并且把它输出到另一个文件里-查看滚动日志-在一个目录下查找大于50M的文件-根据端口号去杀死某一个进程
1.linux查看头两行.查看最后两行 使用head(查看前几行).tail(查看末尾几行).eg:查看/home/wenjian1的前10行内容,应该是:# head -n 10 /home/wen ...
- MongoDB 副本集(Replica Set)
副本集(Replica Set) 副本集概念 此集群拥有一个主节点(Master)和多个从节点(Slave),与主从复制模式类似,但是副本集与主从复制的区别在于:当集群中主节点发生故障时,副本集可以自 ...
- 群晖Video Station不支持部分视频的解释
网络上都是替换ffmpeg插件的做法,无非就是替换了3个文件,然后再对其中一个文件进行修改. 然而在DSM7.0.1+VS3.0.2中,这个方法根本无用,最好的结果是之前无法播放的视频播放起来转圈圈而 ...
- DevOps Gitlab环境部署
DevOps 介绍 目录 DevOps 介绍 一.DevOps 介绍 1.1.1 DevOps 介绍 1.1.2 CI/CD简介 1.1.2 Gitlab安装与使用 一.DevOps 介绍 1.1.1 ...
- 六、js创建页码器:分页、上一页下一页、省略页码
表格数据太多,需要做成分页.因此需要写一个页码器. 1,初始化页码 获取数据之后渲染页码器,页码器初始化,小于6页的全部展示,否则展示前四页,后面是省略号,最后展示尾页.默认选中第一页,禁用前一页的箭 ...
- spark命令
spark提交任务命令 集群方式: ./bin/spark-submit --master spark://localhost:7077 --class 类 /home/cjj/testfile/f ...
- 面向对象ooDay8
精华笔记: 接口: 是一种数据类型(引用类型) 由interface定义 只能包含常量和抽象方法(所有数据默认都是常量,所有方法默认都是抽象的) 接口不能被实例化 接口是需要被实现/继承的,实现/派生 ...
- 跨域获取iframe页面的url
一:跨域获取iframe页面的url 1.在使用iframe页面的js添加以下内容 <script> var host = window.location.href; var histor ...
- 小白开始成长了+洛谷1488与CF629A Far Relative’s Birthday Cake题解
终于开始我的博客生活了,希望博客可以让我记住学了什么,错了什么,接下来会有什么将出现. 记录写ACM生涯中的一些经验和网工经验吧,如果有人看我博客的话,希望可以留言给我提提意见,指导指导我啦~~~ 正 ...
- mongoose Schema字段的含义
var schema3 = new Schema({ test: { type: String, lowercase: true, // 总是将test的值转化为小写 uppercase: true, ...