- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在开始之前,老周先祝各个次元的伙伴们新春快乐、生活愉快、万事如意.
在上一篇水文中,老周介绍了角色授权的一些内容。本篇咱们来聊一个比较实际的问题——把用于授权的角色名称放到外部配置,不要硬编码,以方便后期修改.
由于要配置的东西比较简单,咱们并不需要存在数据库,而是用 JSON 文件配置就可以了。将授权策略和角色列表关联起来。比如,老周这里有个 authorRoles.json 文件,它的内容如下:
{ "cust1" : { "roles": ["admin", "supperuser" ] }, "cust2" : { "roles": ["user", "web", "logger" ] } }
其中,cust1、cust2 是策略名称,所以上面就配置了两个授权策略。每个策略下有个 roles 属性,它的值是数组,这个数组用来指定此策略下允许的角色列表。故:cust1 策略下允许admin、supperuser两种角色的用户访问;cust2 策略下允许 user、web、logger 角色的用户访问.
在 WebApplicationBuilder 的配置中,咱们可以单独加载 authorRoles.json 文件中的内容,然后根据配置文件内容动态添加授权策略.
1、先把配置文件中的内容读出来.
// 配置文件名 const string roleConfigFile = " authorRoles.json " ; // 单独加载配置 IConfigurationBuilder configBuilder = new ConfigurationBuilder(); // 添加配置源,此处是JSON文件 configBuilder.AddJsonFile(roleConfigFile); // 生成配置树对象 IConfiguration myconfig = configBuilder.Build();
此时,myconfig 变量中就包含了 authorRoles.json 文件的内容了.
2、动态添加授权策略.
var builder = WebApplication.CreateBuilder(args); // 根据配置文件的内容来设置授权策略 builder.Services.AddAuthorization(opt => { foreach (IConfigurationSection cc in myconfig.GetChildren()) { var policyName = cc.Key; opt.AddPolicy(policyName, pbd => { // 获取子节点 var roles = cc.GetSection( " roles " ); // 取出角色名称列表 string []? roleslist = roles.Get< string []> (); if (roleslist is not null ) { // 添加角色 pbd.RequireRole(roleslist); // 关联验证架构 pbd.AddAuthenticationSchemes(CustAuthenticationSchemeDefault.SchemeName); } }); } });
在读配置的时候,GetChildren 方法会返回两个节点:cust1 和 cust2。然后用 GetSection 再读下一层,即 roles。接着用 Get 方法就能把字符串数组类型的角色列表读出来了.
这里关联了一个验证架构(或叫验证方案),这个验证架构是老周自己写的,主要是为了简单。老周这个示例是用 Web API 的形式呈现的,所以,不用 Cookie,而是用一个简单的 Token,调用时附加在 URL 的查询字符串中传递给服务器.
如果你的项目的 Token 只是在自己项目中用,不用遵守通用标准,你完全可以自己生成。生成方式你看着办,比如用随机字节什么的都行。在 Token 中不要带密码等安全信息。毕竟,Token 这种东西你说安全,也不见得多安全,别人只要拿到你的 Token 就可以代替你访问服务器。当然你会说,我把 Token 加密再传输。其实别人盗你的 Token 根本不需要知道明文,人家只要按照正确的传递方式(如 Query String、Cookies 等),把你加密后的 Token 放上去,也可以冒用你身份的。所以,很多开放平台都会分配给你 App Key 和密钥,并且强调你的密钥必须保管好,不能让别人知道.
下面看看老周自己写的验证.
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; public class CustAuthenticationHandler : IAuthenticationHandler { #pragma warning disable CS8618 private HttpContext HttpContext { set ; get ; } private AuthenticationScheme Scheme { get ; set ; } #pragma warning restore CS8618 public Task<AuthenticateResult> AuthenticateAsync() { // 获取配置的Token IConfiguration appconfig = HttpContext.RequestServices.GetRequiredService<IConfiguration> (); string []? tks = appconfig.GetSection( " custAuthen:tokens " ).Get< string []> (); if (tks != null && tks.Length > 0 && HttpContext.Request.Query.TryGetValue( " token " , out var reqToken)) { // 看看有没有效 if (!tks.Any(t => t == reqToken)) { return Task.FromResult(AuthenticateResult.Fail( " 未提供有效的Token " )); } // 成功 var tickit = new AuthenticationTicket(HttpContext.User, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(tickit)); } return Task.FromResult(AuthenticateResult.NoResult()); } public Task ChallengeAsync(AuthenticationProperties? properties) { HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.CompletedTask; } public Task ForbidAsync(AuthenticationProperties? properties) { HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; return Task.CompletedTask; } public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) { if (context == null ) throw new ArgumentNullException( " context " ); HttpContext = context; Scheme = scheme; // 看看验证架构是否一致 if (! scheme.Name.Equals(CustAuthenticationSchemeDefault.SchemeName, StringComparison.OrdinalIgnoreCase)) { throw new Exception( " 验证架构不一致 " ); } return Task.CompletedTask; } } public static class CustAuthenticationSchemeDefault { public readonly static string SchemeName = " CustToken " ; }
这里老周没有用什么高级算法生成 Token,而是四个字符串(字符串也是随便输入的),表示四个 Token,只要有一个匹配就算是验证成功了。这些 Token 全写在 appsettings.json 里面.
{ "Logging" : { …… } }, "AllowedHosts": "*" , "custAuthen" : { "tokens" : [ "662CV08Y4GHXOP3" , "BI4C68DLO2HOS0D" , "7GSEJ0J8F0246K5" , "O9FG6V974KWO9G8" ] } }
所以,访问这四个 Token 的配置路径就是 custAuthen:tokens.
在实现 ForbidAsync 和 ChallengeAsync 方法时,不要调用 HttpContext 的扩展方法 ForbidAsync、ChallengeAsync,因为这些扩展方法内部是通过调用 AuthenticationService 类的 ForbidAsync、ChallengeAsync 方法实现的。最终又会回过头来调用 CustAuthenticationHandler 类的 ChallengeAsync、ForbidAsync 方法。这等于转了一圈,到头来自己调用自己,易造成无限递归。所以这里我只设置一个 Status Code 就好了.
在服务容器上注册一下自定义的验证处理方案.
var builder = WebApplication.CreateBuilder(args); // 添加验证功能 builder.Services.AddAuthentication(opt => { // 注册验证架构(方案) opt.AddScheme<CustAuthenticationHandler>(CustAuthenticationSchemeDefault.SchemeName, displayName: null ) ; });
所以,整个应用程序的初始化代码就是这样.
// 配置文件名 const string roleConfigFile = " authorRoles.json " ; // 单独加载配置 IConfigurationBuilder configBuilder = new ConfigurationBuilder(); // 添加配置源,此处是JSON文件 configBuilder.AddJsonFile(roleConfigFile); // 生成配置树对象 IConfiguration myconfig = configBuilder.Build(); var builder = WebApplication.CreateBuilder(args); // 添加验证功能 builder.Services.AddAuthentication(opt => { // 注册验证架构(方案) opt.AddScheme<CustAuthenticationHandler>(CustAuthenticationSchemeDefault.SchemeName, displayName: null ); }); // 根据配置文件的内容来设置授权策略 builder.Services.AddAuthorization(opt => { foreach (IConfigurationSection cc in myconfig.GetChildren()) { var policyName = cc.Key; opt.AddPolicy(policyName, pbd => { // 获取子节点 var roles = cc.GetSection( " roles " ); // 取出角色名称列表 string []? roleslist = roles.Get< string []> (); if (roleslist is not null ) { // 添加角色 pbd.RequireRole(roleslist); // 关联验证架构 pbd.AddAuthenticationSchemes(CustAuthenticationSchemeDefault.SchemeName); } }); } }); builder.Services.AddControllers(); var app = builder.Build();
。
之后,是配置中间件管道。为了简单演示,老周没有写用于身份验证的 Web API,而是直接通过 URL 参数来提供当前访问者的角色。实际开发中不能这样做,而应该从数据库中根据用户查询出用户的角色。但此处是为了演示的简单,也是为了延长键盘寿命,就不建数据库了,不然完成这个示例需要一坤年的时间.
不过,咱们知道,授权是用 Claim 来收集信息的,所以,要在授权执行之前收集好信息。我这里用一个中间件,在授权和调用 API 之前执行.
app.Use((context, next) => { var val = context.Request.Query[ " role " ]; string ? role = val.FirstOrDefault(); if (role != null ) { ClaimsIdentity id = new ( new [] { new Claim(ClaimTypes.Role, role) } /* , CustAuthenticationSchemeDefault.SchemeName */ ); ClaimsPrincipal p = new (id); context.User = p; } return next(); });
由于 WebApplication 对象默认帮我们调用了 UseRouting 和 UseEndpoints 方法。Web API 在访问时路由的是 MVC 控制器,直接走 End point 路线,会导致咱们上面的 Use 方法设置用户角色的中间件不执行。所以要重新调用 UseRouting 和 UseAuthorization 方法.
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
。
用一个名为 Demo 的控制器来做验证.
[Route( " api/[controller] " )] [ApiController] public class DemoController : ControllerBase { [HttpGet( " backup " )] [ Authorize( " cust1 " ) ] public string Backup() => " 备份完成 " ; [HttpGet( " hello/{name} " )] [ Authorize( " cust2 " ) ] public string Hello( string name) { return $ " 你好,{name} " ; } }
cust1、cust2 正是咱们前面配置里的节点名称,即策略名称。例如,调用 Hello 方法使用 cust2 授权策略,它配置的角色为 user、web、loggor.
。
在调用这些 API 时,URL需要携带两个参数:
1、role:用户角色; 。
2、token:用于验证.
用 http-repl 工具先测试 demo/backup 方法的调用.
get /api/demo/backup?
role=web
&token=O9FG6V974KWO9G8
上述调用提供的用户角色为 web,根据前面的配置,web 角色应使用 cust2 策略。但 Backup 方法应用的授权策略是 cust1,因此无权访问,返回 403.
咱们改一下,使用角色为 admin 的用户.
get /api/demo/backup?
role=admin
&token=O9FG6V974KWO9G8
此时,授权通过,返回 200.
。
。
访问 Hello 方法也一样,授权策略是 cust2,允许的角色是 user、web、logger.
get /api/demo/hello/小红?
role=web
&token=BI4C68DLO2HOS0D
授权通过,返回 200 状态码.
。
。
用配置文件来设置角色,算是一种简单方案。如果授权需要的角色有变化,只要修改配置文件中的角列表就行。当然,像 cust1、cust2 等策略名称要事先规划好,策略名称不随便改.
有大伙伴会说,干脆连MVC控制器或其方法上应用哪个授权策略也转到配置文件中,岂不美哉!好是好,但不好弄。可以要自己写个授权的 Filter,主要问题是自己写有时候没有官方内置的代码严谨,容易出“八阿哥”.
所以,综合复杂性与灵活性的平衡,在不扩展现有接口的前提下,咱们这个示例是比较好的,至少,咱们可以在配置文件中修改角色列表.
最后此篇关于【ASP.NETCore】用配置文件来设置授权角色的文章就讲到这里了,如果你想了解更多关于【ASP.NETCore】用配置文件来设置授权角色的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我们需要实现如下授权规则。 如果用户是 super 管理员,则向他提供所有客户信息。比如订单信息。如果用户是客户管理员,只提供他自己的客户信息。等等 我们计划在 DAO 层实现过滤。 创建通用设计来处
我有 https 设置的 Spring Security。 尝试以安全方式在 URL 上运行 curl GET 时,我看到了意外行为。 当 curl 第一次向服务器发送请求时,它没有授权数据(为什么?
关闭。这个问题是 opinion-based 。它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它。 1年前关闭。 Improve thi
我正在构建以下内容: 一个 JavaScript 单页应用程序; 一个暴露 RESTful API 的 Node.js 后端,它将存储用户数据; 用户凭据(电子邮件/密码)可以通过单页应用程序创建并存
在带有RESTful Web服务的Spring Boot应用程序中,我已将Spring Security与Spring Social和SpringSocialConfigurer一起配置。 现在,我有
我正在为真实世界组织的成员在 Rails 中构建一个基于社区的站点。我正在努力遵循 RESTful 设计的最佳实践,其中大部分或多或少是书本上的。使我的大脑在整洁的 RESTful 圈子中运转的问题是
我想启用 ABAC mode对于我在 Google 容器引擎中使用的 Kubernetes 集群。 (更具体地说,我想限制自动分配给所有 Pod 的默认服务帐户对 API 服务的访问)。但是,由于 -
奇怪的事情 - 在 git push gitosis 上不会将新用户的 key 添加到/home/git/.ssh/authorized_keys。当然-我可以手动添加 key ,但这不好:( 我能做
我很好奇您提供 的顺序是否正确和元素中的元素重要吗? 最佳答案 是的,顺序很重要。本页介绍了基本原理:http://msdn.microsoft.com/en-us/library/wce3kxhd
我阅读了如何使用 @login_required 的说明以及其他带有解析器的装饰器。但是,如果不使用显式解析器(而是使用默认解析器),如何实现类似的访问控制? 就我而言,我将 Graphite 烯与
我用 php 开发了一个审核应用程序,通过它我可以审核所有帖子和评论。我还可以选择在 Facebook 粉丝页面墙上发布帖子。但是,当我尝试这样做时,会引发异常,显示“用户尚未授权应用程序执行此操作”
我使用 jquery-ajax 方法 POST 来发布授权 header ,但 Firebug 显示错误“401 Unauthorized” header 作为该方法的参数。 我做错了什么?我该怎么办
我有两组用户,一组正在招聘,一组正在招聘。 我想限制每个用户组对某些页面的访问,但是当我在 Controller 中使用 [Authorize] 时,它允许访问任何已登录的用户而不区分他们来自哪个组?
我有一个简单直接的授权实现。好吧,我只是认为我这样做,并且我想确保这是正确的方法。 在我的数据库中,我有如下表:users、roles、user_role、permissions、 role_perm
我的 soap 连接代码: MessageFactory msgFactory = MessageFactory.newInstance(); SOAPMessage message
我想知道是否可以将 mysql 用户设置为只对数据库中的特定表或列具有读取权限? 最佳答案 是的,您可以使用 GRANT 为数据库在细粒度级别执行此操作。见 http://dev.mysql.com/
我试图获得发布流和离线访问的授权,但出现此错误。 而且它没有显示我想要获得的权限。我的代码如下: self.fb = [[Facebook alloc] initWithAppId:@"xxxxxxx
我是 NodeJS 的初学者,我尝试使用 NodeJS + Express 制作身份验证表单。我想对我的密码进行验证(当“confirmpassword”与“password”不同时,它应该不返回任何
我能够为测试 paypal 帐户成功生成访问 token 和 TokenSecret。然而,下一步是为调用创建授权 header 。 在这种情况下,我需要提供我不确定的 Oauth 签名或 API 签
我正在尝试获取授权 steam 页面的 html 代码,但我无法登录。我的代码是 public string tryLogin(string EXP, string MOD, string TIME)
我是一名优秀的程序员,十分优秀!