认证授权方案之授权初识

1.前言

回顾:认证授权方案之JwtBearer认证

                              

在上一篇中,我们通过JwtBearer的方式认证,了解在认证时,都是基于Claim的,因此我们可以通过用户令牌获取到用户的Claims,在授权过程中对这些Claims进行验证,从而来判断是否具有获取或执行目标资源操作的权限。本章就来介绍一下 ASP.NET Core 的授权系统的简单使用。

2.说明

授权与身份认证是相互独立,但是,授权却需要一种身份验证机制,因此,身份验证可以为当前用户创建一个或多个标识,是确定用户真实身份的过程。而授权是根据标识确定用户可执行的操作的过程,其本质就是具有某种特性的用户会有权限访问某个资源或者执行某个操作。例如:一个拥有管理员身份的用户有创建人员、删除人员、编辑人员和删除人员的操作权限,而一个非管理身份的用户仅有读取自己信息的权限。

这时候,你可能会问,究竟怎样特性的用户可以被授权访问某个资源或执行某个操作。由此我们引出了授权策略的方式,可以根据用户拥有的角色,也可以根据用户的职位,部门甚至是性别,年龄等等特性进行授权。

通过建立授权策略方式,检验认证的用户所携带的身份声明(ClaimsPrincipal对象)与授权策略是否一致,从而确定用户可否执行操作。

3.授权

3.1.  基于角色

3.1.1 添加角色

将角色赋予某个控制器或控制器内的操作,指定当前用户必须是其角色才能访问请求资源。

可以使用Authorize属性的Roles特性指定所请求资源的角色。

例如:

  • 分配了“admin”角色用户进行访问操作

[Authorize(Roles ="admin")]
public class WeatherForecastController : ControllerBase
{}
  • 以逗号分隔角色名来允行多个角色访问操作

[Authorize(Roles ="admin,user")]
public class WeatherForecastController : ControllerBase
{}

其中只要满足admmin或者user其一就可以进行访问。

  • 同时满足指定的多个角色进行的访问操作

[Authorize(Roles = "admin")]
[Authorize(Roles = "user")]
public class WeatherForecastController : ControllerBase
{
}

3.1.2 添加策略的角色

可以创建策略的方式进行访问控制,在配置授权服务中添加注册授权服务策略。

在Startup.cs文件中,通过ConfigureServices()配置服务,创建一个允许具有admin角色的用户才能进行访问的策略

    public void ConfigureServices(IServiceCollection services){services.AddControllers();//添加授权角色策略services.AddAuthorization(options =>{options.AddPolicy("BaseRole", options => options.RequireRole("admin"));});//或者指定多个允许的角色//services.AddAuthorization(options =>// {//    options.AddPolicy("MoreBaseRole", options => options.RequireRole("admin","user"));// });}

在控制器方法使用特性Policy的属性进行策略应用

    [Authorize(Policy = "BaseRole")]public class WeatherForecastController : ControllerBase{}

3.2. 基于声明

3.2.1添加声明

对当前用户必须拥有的声明,并将声明赋予某个控制器或控制器内的操作,因此,指定声明必须持有对应的值才能访问请求资源。

声明要求基于策略,所以必须进行构建一个表示声明要求的策略,才能进行授权。

最简单的类型声明是将判断声明是否存在,而不检查值。

可以创建策略的方式进行访问控制,在配置授权服务中添加注册授权服务策略。

在Startup.cs文件中,通过ConfigureServices()配置服务,创建一个允许具有声明的用户才能进行访问的策略

    public void ConfigureServices(IServiceCollection services){services.AddControllers();//添加基于声明的授权services.AddAuthorization(options =>{options.AddPolicy("BaseClaims", options => options.RequireClaim("name"));});}

BaseClaims声明策略会检查name当前标识是否存在声明。

在控制器方法使用特性Policy的属性进行策略应用

    [Authorize(Policy = "BaseClaims")]public class WeatherForecastController : ControllerBase{}

但是,大多时候,我们需要声明包含值,只有指定允许值的列表,才能授权成功。所以,可以添加指定值。

    public void ConfigureServices(IServiceCollection services){services.AddControllers();//添加基于声明的授权,指定允许值列表。services.AddAuthorization(options =>{options.AddPolicy("BaseClaims", options => options.RequireClaim("name","i3yuan"));});}

3.3 基于策略

上面介绍的基于角色和基于声明的授权,都使用了要求、要求处理程序和预配置的策略。这些在构建上提供了便捷,但是最终都是生成授权策略。ASP.NET Core,设计了另一种灵活的授权方式,一种更丰富的可重复使用的授权结构,基于策略的授权,同时这也是授权的核心。

这节会先讲一下授权策略的应用,在下一节中,会对授权策略的核心进行一步步的详解。

在上面我们简单的介绍了基于策略的角色授权,但是这种方式无非基于角色或者声明多一些。

因此,这里我们基于自定义策略授权的方式,实现授权。

自定义授权,就要我们自己写策略提供器,自己根据不同的参数来生成不同的策略,重新实现策略的方式。策略要求由以下两种元素组成:仅保留数据的要求类,以及对用户验证数据的授权处理程序。创建自定义要求,还可以进一步表达特定策略。

3.3.1. 定义权限策略PermissionRequirement

定义一个权限策略,这个策略并包含一些属性。

public class PermissionRequirement: IAuthorizationRequirement
{public string _permissionName { get; }public PermissionRequirement(string PermissionName){_permissionName = PermissionName;}
}

3.3.2. 再定义一个策略处理类

public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>
{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement){var role = context.User.FindFirst(c => c.Type == ClaimTypes.Role);if (role != null){var roleValue = role.Value;if (roleValue==requirement._permissionName){context.Succeed(requirement);}}return Task.CompletedTask;

授权处理程序读取与角色用户关联的声明,并检查自定义的角色,如果角色匹则成功,否则无法返回成功。

这里的自定义声明是写固定了,但是也可以通过数据库或外部服务的方式进行运行查询获取用户相关角色信息相对应的判断条件,从而在处理程序中进行判断处理。

授权处理程序调用方法 Succeed,同时传递当前要求,以通知此要求已成功得到验证。如果没有传递要求,处理程序无需执行任何操作,可以直接返回内容。不过,如果处理程序要确定是否不符合要求(无论其他处理程序是否已成功验证同一要求),将会对授权上下文对象调用方法 Fail

3.3.3. 下面展示了如何将自定义要求添加到策略

(请注意,由于这是自定义要求,因此没有扩展方法,而必须继续处理策略对象的整个 Requirements 集合):

    public void ConfigureServices(IServiceCollection services){services.AddControllers();//基于自定义策略授权services.AddAuthorization(options =>{options.AddPolicy("customizePermisson",policy => policy.Requirements.Add(new PermissionRequirement("admin")));});//此外,还需要在 IAuthorizationHandler 类型的范围内向 DI 系统注册新的处理程序:services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();// 如前所述,要求可包含多个处理程序。如果为授权层的同一要求向 DI 系统注册多个处理程序,有一个成功就足够了。}

3.3.4. 应用自定义的策略的特性

指定当前用户必须是应用对控制器或控制器内的操作,如

   [Authorize(Policy = "customizePermisson")]public class WeatherForecastController : ControllerBase{}

4.场景

在上一篇认证授权方案之JwtBearer认证中,我们已经实现了获取token的方式,这一次,我们实现一个以基于角色场景为例的认证授权。

在原来生成token的方式中,添加多一个声明角色的Claim,如下:

new Claim(JwtClaimTypes.Role,"admin")

    [HttpGet]public IActionResult GetToken(){try{//定义发行人issuerstring iss = "JWTBearer.Auth";//定义受众人audiencestring aud = "api.auth";//定义许多种的声明Claim,信息存储部分,Claims的实体一般包含用户和一些元数据IEnumerable<Claim> claims = new Claim[]{new Claim(JwtClaimTypes.Id,"1"),new Claim(JwtClaimTypes.Name,"i3yuan"),new Claim(JwtClaimTypes.Role,"admin"),};//notBefore  生效时间// long nbf =new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();var nbf = DateTime.UtcNow;//expires   //过期时间// long Exp = new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds();var Exp = DateTime.UtcNow.AddSeconds(1000);//signingCredentials  签名凭证string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的长度必须 大于等于 16个字符var secret = Encoding.UTF8.GetBytes(sign);var key = new SymmetricSecurityKey(secret);var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//String issuer = default(String), String audience = default(String), IEnumerable<Claim> claims = null, Nullable<DateTime> notBefore = default(Nullable<DateTime>), Nullable<DateTime> expires = default(Nullable<DateTime>), SigningCredentials signingCredentials = nullvar jwt = new JwtSecurityToken(issuer: iss, audience: aud, claims:claims,notBefore:nbf,expires:Exp, signingCredentials: signcreds);var JwtHander = new JwtSecurityTokenHandler();var token = JwtHander.WriteToken(jwt);return Ok(new{access_token = token,token_type = "Bearer",});}catch (Exception ex){throw;}}

对控制器或控制器内的操作,指定当前用户必须是其角色才能访问请求资源,如WeatherForecastController.cs

[ApiController]
[Route("[controller]")]
[Authorize(Roles ="admin")]
public class WeatherForecastController : ControllerBase
{private static readonly string[] Summaries = new[]{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};private readonly ILogger<WeatherForecastController> _logger;public WeatherForecastController(ILogger<WeatherForecastController> logger){_logger = logger;}[HttpGet]public IEnumerable<WeatherForecast> Get(){var rng = new Random();return Enumerable.Range(1, 5).Select(index => new WeatherForecast{Date = DateTime.Now.AddDays(index),TemperatureC = rng.Next(-20, 55),Summary = Summaries[rng.Next(Summaries.Length)]}).ToArray();}
}

5.运行

5.1. 获取token

分别获取role为admin和role为user的情况下颁发的token,只有在角色为admin的情况下才能授权通过。

5.2. 授权资源接口访问

在role为admin的情况下

在role为user的情况下

由上可知,只有在角色为admin的情况下,才能访问目标资源进行操作。

6.总结

  1. 从上一篇的认证到这一篇的授权阶段,简单的介绍了Asp.net Core的认证授权系统,对授权有了初步的认识以及使用,对授权进行划分为两种,一种是基于角色的授权,但随着角色的增加会对处理授权产生限制,不适合表达复杂的授权逻辑。另一种是基于策略的身份验证,策略包含一系列基于声明的要求,以及基于可从 HTTP 上下文或外部源注入的其他任何信息的自定义逻辑。这些要求各自与一个或多个处理程序相关联,这些处理程序负责要求的实际计算。

  2. 可以发现,asp.net core提供的授权策略是一个非常强大丰富且灵活的认证授权方案,能够满足大部分的授权场景。

  3. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。

  4. 因此,在后续的篇章中,会继续探索授权系统,对授权策略的核心进行一步步的详解。

  5. 本示例源码地址

参考文献文档

往期精彩回顾

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[数据结构]树、森林与二叉树之间的相互转换方法

树、二叉树与森林的相互转换 本文只给出树、森林与二叉树之间的转换方法&#xff0c;而详细的证明过程不在本文讨论范围之内。 树 → 二叉树 在所有兄弟结点之间加一连线。 对每个结点&#xff0c;除了保留与其长子的连线外&#xff0c;去掉该结点与其它孩子的连线。 二叉树 …

lua split实现(lua程序设计10.6练习10.1题)

lua split实现&#xff08;lua程序设计10.6练习10.1题&#xff09; local function split(s,sp)local t {}local last 1local irepeati string.find(s,sp,last,true)if i thenif i ~ last thent[#t1] string.sub(s,last,i-1)endlast i1elseif last < #s thent[#t1] s…

Blazor.Server以正确的方式集成Ids4

&#xff08;一个真正的以后端形式来集成认证中心的方案&#xff09;❤本文导读首先特别感谢张善友老师提供技术指导&#xff0c;源于上周我发了一篇文章《[Mvp.Blazor] 集成Ids4&#xff0c;实现统一授权认证》&#xff0c;我本来是想通过像vue框架那样&#xff0c;通过引oidc…

lua transliterate实现(lua程序设计10.6练习10.3题)

lua transliterate实现&#xff08;lua程序设计10.6练习10.3题&#xff09; local function transliterate(s,t)return (string.gsub(s,"%a",function(a)if t[a] false thenreturn ""elseif t[a] thenreturn t[a]endend)) endlocal s "hello world…

作为一个有理想的程序员,必读的书都有哪些?

很多程序员朋友问我&#xff1a;“哪本最具影响力的书&#xff0c;是每个程序员都应该读的&#xff1f;” 笔者从事软件开发15年&#xff0c;看过的计算机相关的书籍不下百本了&#xff0c;如果非要推荐的话&#xff0c;给大家精选以下10本&#xff0c;希望对大家有所帮助&…

认证授权方案之JwtBearer认证

1.前言回顾&#xff1a;认证方案之初步认识JWT在现代Web应用程序中&#xff0c;即分为前端与后端两大部分。当前前后端的趋势日益剧增&#xff0c;前端设备&#xff08;手机、平板、电脑、及其他设备&#xff09;层出不穷。因此&#xff0c;为了方便满足前端设备与后端进行通讯…

使用过滤器模式,让客户关怀中的代码更加干净整洁

一&#xff1a;实际场景介绍我们在给用户做订单催付通知的时候&#xff0c;会有这样的一种场景&#xff0c;用户在系统后台设置一组可以催付的规则&#xff0c;比如说订单金额大于xx元&#xff0c;非黑名单用户&#xff0c;来自哪个地区&#xff0c;已购买过某个商品&#xff0…

C++实现各种排序以及复杂度,稳定性分析

代码如下: #include<iostream> using namespace std;void Bubble_Sort(int *a, int n) {bool flag;int tmp 0;for (int i n - 1; i > 0; i--){flag false;for (int j 0; j < i; j){if (a[j] > a[j 1]){swap(a[j], a[j 1]);flag true;}}if (!flag) break…

Webapi管理和性能测试工具WebBenchmark

WebBenchmark是一款基于开源通讯组件Beetlex扩展的Webapi管理和性能测试工具&#xff0c;在传统工具中一般管理工具缺乏性能压测能力或有性能压测的缺少管理功能&#xff1b;WebBenchmark的设计目标是就管理和性能测试能力同时具备。接下来介绍一下工具的功能和使用&#xff1a…

Abstract Factory(抽象工厂)--对象创建模式

Abstract Factory &#xff08;抽象工厂&#xff09;–对象创建模式 一、意图 提供一个创建一系列相关或者相互依赖的接口&#xff0c;而无需指定它们具体的类。 二、动机 1.在软件系统中&#xff0c;经常面临着“一系列相互依赖的对象”的创建工 作;同时&#xff0c;由于需求…

数据、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构、抽象数据类型的概念

数据&#xff1a; 是客观事物的符号表示&#xff0c;指所有能输入到计算机中并被计算机程序处理的符号的总称。如数学计算中用到的整数和实数&#xff0c;文本编辑所用到的字符串&#xff0c;多媒体程序处理的图形、图像、声音、动画等通过特殊编码定义后的数据。 数据元素&a…

Builder(生成器)--对象创建型模式

Builder&#xff08;生成器&#xff09;–对象创建型模式 一、意图 将一个复杂的对象构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 二、动机 1.在软件系统中&#xff0c;有时候面临着“一个复杂对象”的创建工作&#xff0c;其通常由各个部分的子对…

Gartner:缺乏技术人才将影响企业数字化转型

导语大多数公司在数字化转型的阶段对所需的技能方面都处于“盲目”状态。正文随着COVID-19响应加快了数字化转型的速度和规模&#xff0c;缺乏数字化技能可能会危害人才计划不统一的公司。甚至在冠状病毒大流行之前&#xff0c;董事会就将数字/技术中断列为2020年的头等大事&am…

DEBUG org.springframework.web.servlet.DispatcherServlet - Error rendering view [org.thymeleaf.spring

报错信息如下: 报错原因: thymeleaf有一些限制&#xff0c;使用th语言&#xff0c;内容为空就会报错 改成这样解决问题:

一文说通Blazor for Server-Side的项目结构

用C#代替Javascript来做Web应用&#xff0c;是有多爽&#xff1f;今天聊聊 Blazor。Blazor 是一个 Web UI 框架。这个框架允许开发者使用 C# 来创建可运行于浏览器的具有完全交互 UI 的 Web 应用。可以理解为&#xff0c;这是一个 C# 语言的 Vue / Angular / React&#xff0c;…

Factory Method(工厂方法)--对象创建型模式

Factory Method&#xff08;工厂方法&#xff09;–对象创建型模式 一、意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。 二、动机 1.在软件系统中&#xff0c;经常面临着创建对象的工作;由于需求的变化…

[计组]寄存器和存储器的区别

寄存器存在于CPU中&#xff0c;速度很快&#xff0c;数目有限&#xff1b; 存储器是内存&#xff0c;速度稍慢&#xff0c;但数量很大。 寄存器的功能是存储二进制代码&#xff0c;是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码&#xff0c;故存…

全内存的redis用习惯了?那能突破内存限制类redis产品ssdb呢?

首先说一下背景&#xff0c;在双十一的时候&#xff0c;我们系统接受X宝的订单推送&#xff0c;原先的实现方式是使用 redis 的 List 作为推送数据的承载&#xff0c;在非大促的场景下&#xff0c;一切运行正常&#xff0c;内存占用大概3-4G&#xff0c;机器是16G内存。由于提前…

Prototype(原型)--对象创建模式

Prototype&#xff08;原型&#xff09;–对象创建模式 一、意图 用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。 二、动机 1.在软件系统中&#xff0c;经常面临着“某些结构复杂的对象”的创建工作&#xff1b;由于需求的变化&#xff0c;这些…