关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

vs2019 asp.net core 3.x 授权中的概念

发布时间:2020-02-24 00:00:00

   前言

预计是通过三篇来将清楚asp.net core 3.x中的授权:1、基本概念介绍;2、asp.net core 3.x中授权的默认流程;3、扩展。

在完全没有概念的情况下无论是看官方文档还是源码都晕乎乎的,希望本文能帮到你。不过我也是看源码结合官方文档看的,可能有些地方理解不对,所以只作为参考。

要求对asp.net core的基础有所有了解:Host、依赖注入、日志、配置、选项模式、终结点路由、身份验证等。还是推荐A大博客

 

概述

归纳来说授权就是:某人  针对某个资源  可以做什么操作,如:张三   针对销售订单    可以查看、审核、取消等操作

  • 某人:这个好理解,只要登录系统的用户我们就晓得他是谁;额外的他属于某个角色、属于某个部门、甚至我们可以规定年龄段在18-30岁的能干什么,30-50岁的能干啥,这些都属于所属角色、所属部门、所属年龄段都是用户的一个属性,会作为权限判断的一个依据
  • 资源:可以任何形式的资源,比如销售订单、商品、等等;也可以有更复杂的规则,比如金额大于10000以上的,必须经过老总审核这种要求;另外比如一个页面也可以看做是资源,比如是否允许谁可以访问某个页面。对资源的限定也将作为权限判断的一部分
  • 操作:比如上面说的查看、审核、新增、修改..巴拉巴拉...当然操作也作为权限判断的一部分。

除了上面这3个概念外加一个权限判断逻辑,就组成了授权系统。下面逐一介绍asp.net core 3.x中授权系统涉及到的相关概念

注:
功能权限:这是我们通常说的某人(包含所属角色,所属部门等)可以访问某个菜单下的某个按钮
数据权限:上面说的订单金额大于10000的必须要经理角色才可以审核
这个说来也没啥区别,一个按钮通常是对应到mvc中的某个action,所以还是可以看成是操作;金额大于10000,这个也只是对资源的一种选定

还有一种情况,说一个按钮的点击对应到一个action,那么这个按钮到底是看做“操作”呢,还是把这个Action看成是一个页面地址,作为资源呢?这个就看怎么设计了,mvc默认是当做资源。

 

用户标识ClaimsPrincipal

现实生活中,一个人有多种证件,比如身份证、登机牌、就诊卡等,你去到不同的机构需要出示不同的证件,而每张证件上又有不同的信息,比如身份验证上有身份证号、姓名、性别、出示日期等等...  登机牌上有 航班号、座位号之类的。

在asp.net core中,ClaimsPrincipal就代表上面说的这个人,它可能存在多张证件,证件用ClaimsIdentity表示,当然得有一张证件作为主要证件(如身份证);一张证件又包含多条信息,可以用类似字典的形式IDictionary

上面我们一直拿一个人拥有多张证件来举例,其实并不准确,因为对系统来说并不关心是谁登录,可能是一个用户、也可能是一个第三方应用。所以将ClaimsPrincipal理解为一个登录到系统的主体更合理。

在一个系统中可能同时存在多种身份验证方案,比如我们系统本身做了用户管理功能,使用最简单的cookie身份验证方案,或者使用第三方登录,微信、QQ、支付宝账号登录,通常一个身份验证方案可以产生一张证件(ClaimsIdentity),当然某个身份验证方案也可以将获得的Claim添加到一张现有的证件中,这个是灵活的。默认情况下,用户登录时asp.net core会选择设置好的默认身份验证方案做身份验证,本质是创建一个ClaimsPrincipal,并根据当前请求创建一个证件(ClaimsIdentity),然后将此ClaimsIdentity加入到ClaimsPrincipal,最后将这个ClaimsPrincipal设置到HttpContext.User属性上。身份验证不是本篇重点,详细描述参考:《asp.net core 3.x 身份验证-1涉及到的概念》。我们目前只要记住一个字符串代表一个身份验证方案,它可以从当前请求或第三方去获得一张证件(ClaimsIdentity)  

当用户登录后,我们已经可以从HttpContext.User拿到当前用户,里面就包含一张或多张证件,后续的权限判断通常就依赖里面的信息,比如所属角色、所属部门,除了证件的信息我们也可以通过用户id去数据库中查询得到更多用户信息作为权限判断的依据。

 

资源

资源的概念很宽泛,上面说的销售订单、客户档案、属于资源,我们可以控制某个用户是否能查看、新增、审核订单。或者说一个页面也是一种资源,我们希望控制某用户是否能访问某个页面。在asp.net core中直接以object类型来表示资源,因为asp.net core作为一个框架,它不知道将来使用此框架的开发者到底是对什么类型的资源做权限限制。

在我们日常开发中经常在Action上应用AuthorizeAttribute标签来进行授权控制,其实这里就是将这个Action当做资源。由于目前asp.net core 3.x中默认使用终结点路由,所以现在在asp.net core 3.x中的默认授权流程中当前Endpoint就是资源

记住权限判断中不一定需要资源的参与,比如只要用户登录,就允许使用系统中所有功能。此时整个系统就是资源,允许所有操作。

 

授权依据IAuthorizationRequirement

试想这样一种权限需求:要求属于角色"经理"或"系统管理员"的用户可以访问系统任何功能。当我们做权限判断时我们可以从HttpContext.User得到当前用户,从其证件列表中总能找到当前用户的所属角色,那么这里需要进行比较的两个角色"经理"、"系统管理员"从哪里获得呢?
再比如:要求只要当前用户的证件中包含一个"特别通行证"的Calim,就允许他访问系统的任何功能。同上面的情况一样,在判断权限时我们可以知道当前登录用户的Calim列表,那需要进行比对的"特别通行证"这个字符串从哪来呢?

asp.net core将这种权限判断时需要用来比对的数据定义为IAuthorizationRequirement,我这里叫做"授权依据",在一次权限判断中可能会存在多个判断,所以可能需要多个授权依据,文件后面会讲如何定制授权依据

其实某种意义上说“当前用户(及其包含的Calim列表)”也可以看做是一种依据,因为它也是在授权判断过程中需要访问的数据,但是这个我们是直接通过HttpContext.User来获取的,不需要我们来定义。

当我们针对某个页面或Action进行授权时可以直接从当前路由数据中获取Action名,在asp.net core 3.x中甚至更方便,可以在请求管道的早期就能获得当前请求的终结点。所以针对Action的访问也不需要定义成授权依据中

所以授权依据算是一种静态数据,为了更好的理解,下面列出asp.net core中已提供的几种授权依据

  • ClaimsAuthorizationRequirement
public string ClaimType { get; }public IEnumerable<string> AllowedValues { get; }

     将来在权限判断是会判断当前用户的Claim列表中是否包含一个类型为ClaimType的Claim,若AllowedValues有数据,则进一步判断是否完整包含AllowedValues中定义的值

  • DenyAnonymousAuthorizationRequirement:权限判断发现存在这个依据,则直接拒绝匿名用户访问
  • RolesAuthorizationRequirement:这就是最常见的基于角色的授权时会使用的,它定义了 public IEnumerable<string> AllowedRoles { get; } ,将来做权限判断时会看当前用户是否属于这里允许的角色中的一种
  • OperationAuthorizationRequirement:这个也比较常用,在做功能授权时比较常用。它定义了 public string Name { get; set; } ,Name代表当前操作名,比如“Order.Add”就是新增订单,将来权限判断是可以根据当前用户Id、所属角色和"Order.Add"到数据库去做对比
  • AssertionRequirement:这个就更强大了,它定义了  public Func<AuthorizationHandlerContext, Task<bool>> Handler { get; } ,将来权限判断时发现是这个类型,直接调用这个委托来进行权限判断,所以灵活性非常大 

 

授权策略AuthorizationPolicy

策略同时作为身份验证方案授权依据的容器,它包含本次授权需要的数据。

请求抵达时asp.net core会找到默认身份验证方案进行身份验证(根据请求获取用户ClaimsPrincipal),但有时候我们希望由自己来指定本次授权使用哪些身份验证验证方案,而不是使用默认的,这样将来身份验证过程中会调用设置的这几个身份验证方案去获得多张证件,此时HttpContext.User中就包含多张证件。所以授权策略里包含多种身份验证方案。

一次授权可能需要多种判断,比如同时判断所属角色、并且是否包含哪种类型的Calim并且.....,某些判断可能需要对比“授权依据”,所以一个授权策略包含多个授权依据。

另外我们可以将多个授权策略合并成一个对吗?所有的身份验证方案合并,所有的“授权依据”合并

将来授权检查时将根据身份验证方案获取当前用户的多个证件(里面包含很多Cliam可以用作权限判断),然后逐个判断授权依据,若都满足则认为授权检查成功。

若是针对某个资源的授权,授权方法大概是这样定义的xxxx.Authorize(策略,订单),这里不一定直接传入整个订单,可能只传入订单金额,这个根据业务需要。若是简单的情况只判断页面访问权限,则xxx.Authorize(策略),因为当前页面可以直接通过当前请求获取。

在asp.net core 3.x中启动阶段我们可以定义一个授权策略列表,这个看成是全局授权策略,一直存在于应用中。
在应用运行时,每次进行授权时会动态创建一个授权策略,这个策略是最终进行本次授权检查用的,它可能会引用某一个或多个全局策略,所谓的引用就是合并其“身份验证方案”列表和“授权依据列表”,当然其自身的“身份验证方案”列表和“授权依据列表”也是可以定制的,待会在AuthorizeAttribute部分再详细说

 

策略构造器AuthorizationPolicyBuilder

主要用来帮助创建一个授权策略(.net中典型的Builder模式),使用步骤是:

  1. new一个AuthorizationPolicyBuilder
  2. 调用各种方法对策略进行配置
  3. 最后调用Build方法生成最终的授权策略。

下面用伪代码感受下

var builder = new AuthorizationPolicyBuilder();
builder.RequireRole("Manager","Admin");//builder....继续配置var authorizationPolicy = builder.Build();

RequireRole将为最终会生成的策略中的“授权依据”列表加入一个RolesAuthorizationRequirement("Manager","Admin")。其它类似的api就不介绍了。

 

授权处理器AuthorizationHandler

上面说的当前用户、授权依据、以及授权时传递进来的资源都是可以看成是静态的数据,作为授权判断的依据,真正授权的逻辑就是用IAuthorizationHandler来表示的,先看看它的定义

public interface IAuthorizationHandler
{
    Task HandleAsync(AuthorizationHandlerContext context);
}

 

AuthorizationHandlerContext

中包含当前用户、授权依据列表和参与授权判断的资源,前者是根据授权策略中的多个身份验证方案经过身份验证后得到的;后者就是授权策略中的授权依据列表。在方法内部处理成功或失败的结果是直接存储到context对象上的。

一个应用中可以存在多个AuthorizationHandler,在执行授权检查时逐个调用它们进行检查,若都成功则本次授权成功。

 

针对特定授权依据类型  的  授权处理器AuthorizationHandler


/template/Home/Zkeys/PC/Static