.NET CORE 授权
.NET CORE 授权
一、三种方式授权
不论使用NET CORE框架的何种授权都必须引入中间件,因为它实现了在管道中对当前请求的鉴权和授权的验证,在Startup中的Configure中首先加入鉴权和授权的中间件
中间件 | 描述 |
---|---|
UseAuthentication | 鉴权中间件 |
UseAuthorization | 授权中间件,基于鉴权 |
1.Scheme 和 Role
基于Cookie 的Scheme授权,就是在授权时检查下是否存在对应的Scheme,可以使用自定义的Scheme授权,当然此处只是简单介绍Scheme
和Role
授权的方法,在选择使用.NET CORE框架的授权方式时,常用的是Policy
的方式,因为Policy
的扩展性和可配置性是三种方式中最强的,其实归根结底Scheme
和Role
授权方式实现的本质,就是基于Policy
的封装而已,至于是如何实现到后面结合源码来探究,但是在这之前,要知道如何使用它
1.引入中间件并且在IOC容器中注册基于Scheme授权
//在IOC中注册
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/Authorization/Index";
options.AccessDeniedPath = "/Authorization/Index";
}); //在Configure中引入中间件
app.UseAuthentication();
app.UseAuthorization();
2.在对应的API中加入授权特性,特性的策略名AuthenticationSchemes必须和注册IOC的authenticationScheme一致
[Authorize(AuthenticationSchemes = "Cookies")]
public IActionResult Info()
{
return View();
}
3.如果使用角色授权,就需要在登录时写入Claim的Role信息,然后在对应的Api接口上使用时加入[Authorize]特性
[AllowAnonymous]
public IActionResult Login(string name, string password)
{
//用户名密码不正确直接返回
if (!"Admin".Equals(name) || !"123456".Equals(name))
{
return new JsonResult(new{ Result = false,Message = "登录失败" });
} var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
//写入身份信息角色为
claimIdentity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
await base.HttpContext.SignInAsync("Cookies", new ClaimsPrincipal(claimIdentity), new AuthenticationProperties
{
ExpiresUtc = DateTime.UtcNow.AddMinutes(30),
});
return new JsonResult(new{ Result = true,Message = "登录成功"});
} [Authorize(Roles = "Admin")]
public IActionResult InfoAdmin()
{
return View();
}
2.Policy
1.在Ioc中注册2种基于策略的授权
AdminPolicy
和UserPolicy
,在授权AdminPolicy
时会校验Claim的Role的值是“Admin”,Name的值是“美洋洋”,而且必须包含邮箱,在检验UserPolicy
时会验证Claim中是否存在Role这个Key,并且验证Role的值是"User",如果用户鉴权通过的信息中完全符合这些规则的要求,那么授权就会通过services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy",
policyBuilder => policyBuilder
//Claim的Role是Admin
.RequireRole("Admin")
//Claim的Name是美洋洋
.RequireUserName("美洋洋")
////必须有某个Cliam
.RequireClaim(ClaimTypes.Email)
);
options.AddPolicy("UserPolicy",
policyBuilder => policyBuilder.RequireAssertion(context =>
context.User.HasClaim(c => c.Type == ClaimTypes.Role)
&& context.User.Claims.First(c => c.Type.Equals(ClaimTypes.Role)).Value == "User")
);
});
2.我们在控制器中,在需要使用授权的
Action
上,标记授权特性并声明使用Policy
的方式,当客户端访问Action
时管道会自动去检验它的合法性,确定是否授权,注意如果Action
上同时使用了[AllowAnonymous]
,那么就会忽略授权检验,因为[AllowAnonymous]
的优先级是高于[Authorize]
的[Authorize(Policy = "AdminPolicy")]
public IActionResult AdminPolicy()
{
return View();
}
二、源码解读授权流程
1.经过上面几种简单的配置基本知道了3种方式的使用方法,在我们去探究查看他的实现源码之前,我们脑海中应该对它的流程有个大概的构思,如果是我们自己来做这个功能怎么做,一般不管有没有工作经验的朋友,基本都能想出解决方案,只是方案的细节差异或者逻辑严谨以及扩展度不同而已,大概的思路无非大同小异。
- 1.如果是Policy方式提前定义好授权的规则信息,登录成功后存储用户的各项身份信息。
- 2.反射找到控制器上标记的Authorize特性。
- 3.根据特性上给的授权方式和规则以及对应的值 与 用户身份信息中的信息比对来得出是否能访问当前控制器。
2.根据上面4点简单的逻辑可以实现授权,甚至可以说.NET CORE对于授权大致思路也是这么做的,只是他的扩展和可配置以及设计方式是经过详细策划的,以至于实现的更加完整和合理,对于我们,主要思考的问题有如下几点。
1.什么时候注册规则?能不能自定义规则?
2.什么时候找到控制器标注的特性?
3.什么时候对比规则决定是否通过授权?
接下来我们带着我们自己假设性的思路及思考的问题,来查看源码是如何做到的
1.注册解析流程
1.授权注册常用类
1.首先我们需要简单认识一下如下几个类
类名 描述 PolicyServiceCollectionExtensions 用户注册授权服务的扩展类,包含2个AddAuthorization()方法 AuthorizationOptions 用于添加授权时,自定义配置的提供类,他提供了自定义添加策略和查找策略的方法以及存储的属性 AuthorizationPolicyBuilder 用于提供用户配置添加授权规则,再根据规则和Scheme创建AuthorizationPolicy的功能 AuthorizationPolicy AuthorizationPolicy的一个实例,对应一个授权的Policy,它是由AuthorizationPolicyBuilder创建 IAuthorizationRequirement 提供授权规则的接口约束,他的实例Requirement就是具体的授权条件,例如Role授权方式的规则,由它的实例RolesAuthorizationRequirement实现
2.规则源码解析
1.在.NET CORE中授权注入规则是依赖
PolicyServiceCollectionExtensions
扩展类来完成的,他包含了2个重载的AddAuthorization()
,它的第二个重载包含了一个带参的AuthorizationOptions
类型的无返回值委托,我们将从他开始介绍,如果看过WebApi的源码应该知道,我们的Application_Start启动类中,调用的GlobalConfiguration.Configure方法就是这样的风格及设计,至于如果不知道为何使用这种设计方式的话,应该是没有搞清楚委托的本质,建议去真正的理解了委托之后再来看,因为委托单单对于NET CORE来说是功不可没的。2.打开AuthorizationOptions里面,包含了一个值为
AuthorizationPolicy
类型的字典PolicyMap
和重载的AddPolicy()
方法,我们在注册阶段主要介绍PolicyMap
和AddPolicy()
的第二个重载方法,而PolicyMap就是用于存储Policy的,我们看到同样在AddPolicy()时,也将一个无返回值委托作为第二个参数,而委托的参数为AuthorizationPolicyBuilder类型的,而AuthorizationPolicyBuilder
的最终目的,就是用来创建AuthorizationPolicy
和创建规则的。3.打开AuthorizationPolicyBuilder类,有一个IList类型的Requirements属性,他是用于存储用户注册是添加的规则集合,现在看到配置策略的这段代码是不是瞬间就明白了。
- AuthorizationOptions 类中的第二个AddPolicy()方法用于添加一个Policy
- AuthorizationPolicyBuilder 类中RequireUserName()方法用于添加规则,最终加入到AuthorizationPolicyBuilder的Requirements属性中去了
services.AddAuthorization((AuthorizationOptions authorizationOptions) =>
{
authorizationOptions.AddPolicy("CustomPolicy",
(AuthorizationPolicyBuilder authorizationPolicyBuilder) =>
authorizationPolicyBuilder.RequireUserName("懒洋洋"));
})
4.我们看到AuthorizationPolicyBuilder的RequireUserName()方法,他加入的是一个继承自
IAuthorizationRequirement
接口的NameAuthorizationRequirement
,它的作用就是一个验证规则,同理我们根据这个思想,完全可以扩展自己的规则。
3.扩展IAuthorizationRequirement
1.创建一个手机号的校验规则,如果以180和139开头的手机号,那么就能访问某一个Api
public class MobilePhoneRequirement : AuthorizationHandler<MobilePhoneRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MobilePhoneRequirement requirement)
{
if (context.User != null && context.User.HasClaim(c => c.Type == ClaimTypes.MobilePhone))
{
var phone = context.User.FindFirst(c => c.Type == ClaimTypes.MobilePhone).Value;
if (phone.StartsWith("180", StringComparison.OrdinalIgnoreCase) || email.StartsWith("139", StringComparison.OrdinalIgnoreCase))
{
context.Succeed(requirement);
}
else
{
//context.Fail();//没成功就留给别人处理
}
}
return Task.CompletedTask;
}
}2.IOC容器注册及Action绑定授权
//注册服务
services.AddSingleton<IAuthorizationHandler, MobilePhoneRequirement>();
//注册自定义授权策略
services.AddAuthorization((AuthorizationOptions authorizationOptions) =>
{
authorizationOptions.AddPolicy("MobilePhone", policyBuilder => policyBuilder.Requirements.Add(new MobilePhoneRequirement()));
}); //控制器中使用
[Authorize(AuthenticationSchemes = "Cookies", Policy = "MobilePhone")]
public IActionResult InfoMobilePhone()
{
return View();
}
2.授权析流程
1.授权注册常用类
1.如下几个类
类名 描述 AuthorizationMiddleware 授权中间件 IAuthorizationService >DefaultAuthorizationService 授权调用的服务 IAuthorizationPolicyProvider > DefaultAuthorizationPolicyProvider 对于指定的请求,根据规则用于提供对应的Policy IAuthorizationHandlerProvider >DefaultAuthorizationHandlerProvider 提供最终对请求按照规则处理的Handler IPolicyEvaluator > PolicyEvaluator 用于验证鉴权和授权为最终处理的AuthorizationService提供过渡
2.授权部分解析
1.我们想知道最终的请求是如何被授权处理的,所以根据UseAuthorization(),找到授权中间件
AuthorizationMiddleware
,在中间件中实现了对请求的授权检查。
- 首先找到当前被调用目标是否
IAuthorizeData
标记的信息,其实就是查找被Authorize
标记的特性,因为Authorize继承自IAuthorizeData
- 首先找到当前被调用目标是否
- 将IAuthorizeData 信息利用
AuthorizationPolicy
转换为Policy.
- 将IAuthorizeData 信息利用
- 创建一个
IPolicyEvaluator
类型的PolicyEvaluator
实例
- 创建一个
- 将
Context
和Policy
传入PolicyEvaluator的AuthenticateAsync() 进行鉴权验证
返回一个AuthenticateResult
。
- 将
- 判断调用目标是否被
AllowAnonymous
标记,如果标记则直接跳过授权,进行访问
- 判断调用目标是否被
- 调用PolicyEvaluator的AuthorizeAsync()进行
授权验证
,在方法中将处理转交由IAuthorizationService
处理,返回一个PolicyAuthorizationResult
来说明是否授权成功。
- 调用PolicyEvaluator的AuthorizeAsync()进行
2.我们进入
IAuthorizationService
类型的实例DefaultAuthorizationService
中查看
- 1.根据规则,用户,创建Context 上下文。
- 2.根据上下文在
DefaultAuthorizationHandlerProvider
中获取到继承自IAuthorizationHandler
对应的Requirement集合 - 3.循环执行每一个实现
IAuthorizationHandler
的Requirement
.NET CORE 授权的更多相关文章
- 聊聊asp.net core 授权流程
在上一篇 聊聊 asp.net core 认证和授权 中我们提到了认证和授权的基本概念,以及认证和授权的关系及他们之间的协同工作流程,在这篇文章中,我将通过分析asp.net core 3.1 授权流 ...
- 一、Core授权(基于cookie)
一.Core的授权 配置 打开项目中的Startup.cs文件,找到ConfigureServices方法,我们通常在这个方法里面做依赖注入的相关配置.添加如下代码: public void Conf ...
- .Net Core 授权系统组件解析
前面关于.Net Core如何进行用户认证的核心流程介绍完毕之后,.Net Core 认证系统之Cookie认证源码解析远程认证暂时不介绍,后期有时间,我会加上.接下去介绍认证组件是如何和认证组件一起 ...
- .NET Core授权失败如何自定义响应信息?
前言 在.NET 5之前,当授权失败即403时无法很友好的自定义错误信息,以致于比如利用Vue获取到的是空响应,不能很好的处理实际业务,同时涉及到权限粒度控制到控制器.Action,也不能很好的获取对 ...
- 理解ASP.NET Core - 授权(Authorization)
注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 之前,我们已经了解了ASP.NET Core中的身份认证,现在,我们来聊一下授权. 老规矩,示 ...
- 一、Core授权-2 之.net core 基于Jwt实现Token令牌
一.Startup类配置 ConfigureServices中 //添加jwt验证: services.AddAuthentication(JwtBearerDefaults.Authenticati ...
- ASP.NET Core 认证与授权[5]:初识授权
经过前面几章的姗姗学步,我们了解了在 ASP.NET Core 中是如何认证的,终于来到了授权阶段.在认证阶段我们通过用户令牌获取到用户的Claims,而授权便是对这些的Claims的验证,如:是否拥 ...
- ASP.NET Core 认证与授权[6]:授权策略是怎么执行的?
在上一章中,详细介绍了 ASP.NET Core 中的授权策略,在需要授权时,只需要在对应的Controler或者Action上面打上[Authorize]特性,并指定要执行的策略名称即可,但是,授权 ...
- asp.net core系列 49 Identity 授权(上)
一.概述 授权是指用户能够访问资源的权限,如页面数据的查看.编辑.新增.删除.导出.下载等权限.ASP.NET Core 授权提供了多种且灵活的方式,包括:Razor pages授权约定.简单授权.R ...
随机推荐
- IDEA学习系列之Module概念
感谢原文作者:小manong 原文链接:https://www.jianshu.com/p/fcccc37fcb73 简单应用:IDEA Maven创建多个Module相互依赖 1.Module的概念 ...
- WebSocket协议详解及应用
WebSocket协议详解及应用(七)-WebSocket协议关闭帧 本篇介绍WebSocket协议的关闭帧,包括客户端及服务器如何发送并处理关闭帧.关闭帧错误码及错误处理方法.本篇内容主要翻译自RF ...
- windows doc命令复制粘贴文件
# 删除前端文件 rmdir /s/q E:\yuanbo2019\public\static del E:\yuanbo2019\public\index.html @echo off ::被复制的 ...
- js获取高度
转载请注明来源:https://www.cnblogs.com/hookjc/ <script> function getInfo() { var s = ""; s ...
- LaunchScreen&LaunchImage
优先级:LaunchScreen > LaunchImage 在xcode配置了,不起作用 1.清空xcode缓存 2.直接删掉程序 重新运行 如果是通过LaunchImage设置启动界面,那么 ...
- js实现网页回弹小球效果
直接上效果图 运行页面会首先弹出一个输入框,询问用户想要产生的小球数量,随后后台就会产生指定数量的小球,在页面中来回跳动,触碰到页面边框时,就会回弹,且产生的小球颜色随机,小球在页面中的位置随机,小球 ...
- java+selenium脚本编写规范
2. 源文件规范 2.1 文件名 源文件以最顶层的类名来命名,大小写敏感,文件扩展名为.java 2.2 文件编码 UTF-8 源文件要求编码格式为UTF-8 2.3 源文件结 ...
- java中LinkedList ArrayList 数组 HashSet 存储数据测试
话不多少,直接上代码 import java.text.SimpleDateFormat;import java.util.*; public class testList { public stat ...
- 帆软报表(finereport)JS实现cpt中详细单元格刷新
1.刷新固定单元格 setInterval(function(){ //获取第二行第 5 列 E2 单元格对象 var _changeCell = $("tr[tridx=1]" ...
- 震惊!!!!!!!靠sort水过二叉堆的天秀操作