3

公共组件

添加公共类库Demo.Permissions,编辑Demo.Permissions.csproj文件,将 <Project Sdk="Microsoft.NET.Sdk"> 改为:

<Project Sdk="Microsoft.NET.Sdk.Web">

为Demo.Permissions项目添加Nuget引用Volo.Abp.Core和Microsoft.AspNetCore.Http,并应用Demo.Identity.HttpApi.Client项目。

在Demo.Permissions中添加权限关系枚举PermissionRelation如下:

namespace Demo.Permissions;/// <summary>
/// 权限关系枚举
/// </summary>
public enum PermissionRelation
{/// <summary>/// 需要同时满足/// </summary>And,/// <summary>/// 只需要满足任意一项/// </summary>Or,}

在Demo.Permissions中添加CusPermissionAttribute特性,用于标记接口所需要的权限,如下:

namespace Demo.Permissions;/// <summary>
/// 自定义权限特性
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CusPermissionAttribute : Attribute
{/// <summary>/// 权限编码/// </summary>public string[] PermissionCode { get; }/// <summary>/// 权限之间的关系/// </summary>public PermissionRelation Relation { get; } = PermissionRelation.And;/// <summary>/// 构造函数/// </summary>/// <param name="relation">权限关系</param>/// <param name="permissionCodes">权限编码</param>public CusPermissionAttribute(PermissionRelation relation,params string[] permissionCodes){Relation = relation;PermissionCode = permissionCodes;}/// <summary>/// 构造函数/// </summary>/// <param name="permissionCodes">权限编码</param>public CusPermissionAttribute(params string[] permissionCodes){PermissionCode = permissionCodes;}
}

其中一个特性可以声明多个权限码,Relation表示该特性中所有权限码间的关系,如果为And,需要用户具有该特性声明的所有权限码才可通过验证,若为Or,则表示用户只要具有任意一个或多个该特性中声明的权限就可通过验证。

一个接口可以声明多个特性,特性与特性之间是And关系。

在Demo.Permissions中添加权限验证中间件CusPermissionMiddleware如下:

using Demo.Identity.Permissions;
using Microsoft.AspNetCore.Http.Features;
using Volo.Abp.Users;namespace Demo.Permissions;/// <summary>
/// 自定义权限中间件
/// </summary>
public class CusPermissionMiddleware
{private readonly RequestDelegate _next;private readonly ICurrentUser _currentUser;private readonly ISysPermissionAppService _service;public CusPermissionMiddleware(RequestDelegate next, ICurrentUser currentUser, ISysPermissionAppService service){_next = next;_currentUser = currentUser;_service = service;}public async Task InvokeAsync(HttpContext context){var attributes = context.GetEndpoint()?.Metadata.GetOrderedMetadata<CusPermissionAttribute>();//如果不存在CusPermissionAttribute特性则该接口不需要权限验证,直接跳过if (attributes==null||attributes.Count==0){await _next(context);return;}//如果需要权限验证则必须是已登录用户,否则返回401if (_currentUser.Id == null){context.Response.StatusCode = 401;return;}//获取用户权限var userPermisions = (await _service.GetUserPermissionCode((Guid) _currentUser.Id)).ToHashSet();//比对权限 如果无权限则返回403foreach (var cusPermissionAttribute in attributes){var flag = cusPermissionAttribute.Relation == PermissionRelation.And? cusPermissionAttribute.PermissionCode.All(code => userPermisions.Contains(code)): cusPermissionAttribute.PermissionCode.Any(code => userPermisions.Contains(code));if (!flag){context.Response.StatusCode = 403;return;}}await _next(context);}
}

在接口调用时,该中间件会获取接口所声明的权限特性,并调用身份管理服务接口获取当前用户所持有的权限码,按特性顺序依次验证。

在Demo.Permissions中添加PermissionRegistor类,用于在聚合服务启动时读取代码中声明的所有权限码,并注册到身份管理服务。代码如下:

using System.ComponentModel;
using Demo.Identity.Permissions.Dto;namespace Demo.Permissions;/// <summary>
/// 权限注册
/// </summary>
public static class PermissionRegistor
{/// <summary>/// 在指定类型中获取权限集合/// </summary>/// <param name="serviceName">服务名称</param>/// <typeparam name="T">类型</typeparam>/// <returns></returns>internal static List<SysPermissionDto> GetPermissions<T>(string serviceName){List<SysPermissionDto> result = new List<SysPermissionDto>();Type type = typeof(T);var fields = type.GetFields().Where(x=>x.IsPublic&&x.IsStatic);foreach (var field in fields){string code = field.GetValue(null).ToString();string name = "";object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);  //获取描述属性if (objs != null && objs.Length > 0){DescriptionAttribute descriptionAttribute = (DescriptionAttribute) objs[0];name = descriptionAttribute.Description;}string parentCode = null;if (code.Contains(".")){parentCode = code.Substring(0, code.LastIndexOf('.'));}result.Add(new SysPermissionDto(){Name = name,Code = code,ParentCode = parentCode,ServiceName = serviceName,});}return result;}
}

在Demo.Permissions中添加CusPermissionExtensions类,提供IApplicationBuilder的扩展方法,用于注册中间件和注册权限,代码如下:

using Demo.Identity.Permissions;namespace Demo.Permissions;public static class CusPermissionExtensions
{/// <summary>/// 注册自定义权限/// </summary>public static void UseCusPermissions<T>(this IApplicationBuilder app, string serviceName){app.RegistPermissions<T>(serviceName);app.UseMiddleware<CusPermissionMiddleware>();}/// <summary>/// 注册权限/// </summary>/// <param name="app"></param>/// <param name="serviceName">服务名称</param>/// <typeparam name="T"></typeparam>private static async Task RegistPermissions<T>(this IApplicationBuilder app, string serviceName){var service = app.ApplicationServices.GetService<ISysPermissionAppService>();var permissions = PermissionRegistor.GetPermissions<T>(serviceName);await service.RegistPermission(serviceName, permissions);}
}

在Demo.Permissions中添加DemoPermissionsModule类如下:

using Demo.Identity;
using Volo.Abp.Modularity;namespace Demo.Permissions;[DependsOn(typeof(IdentityHttpApiClientModule))]
public class DemoPermissionsModule:AbpModule
{}

4

聚合服务层

在聚合服务层,我们就可以使用刚才创建的Demo.Permissions类库,这里以商城服务为例。

在Demo.Store.Application项目中添加Demo.Permissions的项目引用,并为DemoStoreApplicationModule类添加以下特性:

[DependsOn(typeof(DemoPermissionsModule))]

在Demo.Store.Application项目中添加在PermissionLab类用于声明该服务中用到的所有权限,代码如下

using System.ComponentModel;namespace Demo.Store.Application;/// <summary>
/// 权限列表
/// </summary>
public class PermissionLab
{[Description("订单")]public const string ORDER = "Order";[Description("创建订单")]public const string ORDER_CREATE = $"{ORDER}.Create";[Description("查询订单")]public const string ORDER_SELECT = $"{ORDER}.Select";//添加其他权限 ……
}

这里使用常量定义权限,其中常量的值为权限码,常量名称使用Description特性标记。

在Demo.Store.HttpApi.Host项目配置文件appsettings.json中的RemoteServices中添加身份管理服务地址如下:

"Default": {"BaseUrl": "http://localhost:5000/"
},

在Demo.Store.HttpApi.Host项目DemoStoreHttpApiHostModule类OnApplicationInitialization方法中找到 app.UseRouting(); ,在其后面添加如下内容:

app.UseCusPermissions<PermissionLab>("Store");

这样我们就可以在聚合服务层ApplicationService的方法上添加CusPermission用于声明接口所需要的权限,例如:

/// <summary>
/// 分页查询订单列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
[CusPermission(PermissionLab.ORDER_SELECT)]
public async Task<PagedResultDto<StoreOrderDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{var ret = await _orderAppService.GetListAsync(input);return new PagedResultDto<StoreOrderDto>{TotalCount = ret.TotalCount,Items = ObjectMapper.Map<IReadOnlyList<OrderDto>, List<StoreOrderDto>>(ret.Items)};
}

5

补充说明

完成以上步骤后,我们可以在聚合服务层Admin项目中将身份管理服务中角色权限相关接口封装并暴露给客户端调用,其中注册权限接口仅为聚合服务层注册权限使用,不建议暴露给客户端。

这里我只简单使用了对权限码自身的校验,并未做父子关系的关联校验,在实际项目中,可以依据需要进行修改或扩展。

end

更多精彩

关注我获得

ABP vNext微服务架构详细教程——分布式权限框架(下)相关推荐

  1. ABP vNext微服务架构详细教程——分布式权限框架(上)

    1 简介 ABP vNext框架本身提供了一套权限框架,其功能非常丰富,具体可参考官方文档:https://docs.abp.io/en/abp/latest/Authorization 但是我们使用 ...

  2. ABP vNext微服务架构详细教程——结束语

    ABP vNext微服务架构详细教程--简介 ABP vNext微服务架构详细教程--架构介绍 ABP vNext微服务架构详细教程--身份管理服务 ABP vNext微服务架构详细教程--基础服务层 ...

  3. ABP vNext微服务架构详细教程——项目部署

    1 基础配置 在之前的文章中,我们已经配置了Kubernetes集群并安装了管理工具Kubesphere,文章地址为:https://mp.weixin.qq.com/s/MgpdMv5A-fYxN7 ...

  4. ABP vNext微服务架构详细教程——架构介绍

    总体架构 所有应用服务.API网关.身份认证服务均部署在Kubernetes容器中,由Kubernetes提供应用配置.服务治理.服务监控等功能. 客户端所有访问均通过Kubernetes的Nginx ...

  5. ABP vNext微服务架构详细教程——简介

    简介 该系列文章主要展示ABP vNext框架在微服务架构下的用法,提供一套可落地的技术实现思路,并演示各服务在Kubernetes下的部署方案. 基础概念 ABP vNext 基于ASP.NET C ...

  6. ABP vNext微服务架构详细教程——身份管理服务

    1 框架搭建 ABP vNext创建包含app和module两种模板,其中app方式所创建的模板包含用户.角色.权限管理,ABP基础配置IdentityServer的基础配置数据等功能.module模 ...

  7. ABP vNext微服务架构详细教程——基础服务层

    1 服务创建 在除身份管理相关服务以外的其他业务服务中,我们不需要包含用户角色权限管理功能模块,ABP vNext框架为我们提供了模块模式,其默认模板不包含身份管理相关模块,更适合用于搭建普通的业务微 ...

  8. abp vNext微服务框架分析

    abp vNext新框架的热度一直都很高,于是最近上手将vNext的微服务Demo做了一番研究.我的体验是,vNext的微服务架构确实比较成熟,但是十分难以上手,对于没有微服务开发经验的.net人员来 ...

  9. 【转】abp vNext微服务框架分析

    abp vNext新框架的热度一直都很高,于是最近上手将vNext的微服务Demo做了一番研究.我的体验是,vNext的微服务架构确实比较成熟,但是十分难以上手,对于没有微服务开发经验的.net人员来 ...

最新文章

  1. KMP算法的详细解释及实现
  2. api怎么写_API数据加密框架monkeyapiencrypt
  3. Ajax简要应用说明及技术开发实例
  4. 动态加入JS及加入CSS
  5. b/s c/s结构的区别!
  6. 查看Full GC方法:1,jconsel:2,linux 命令: jstat -gcutil id 4s 10003,linux 命令(前提有.gc日志):c
  7. 转载 用Python实现设计模式——工厂模式
  8. 学习Flask-SQLAlchmy管理数据库知识记录点
  9. MyBatis foreach语句批量插入数据
  10. 优秀的应用快速启动工具:start for Mac完美支持m1
  11. Markdown常用快捷键
  12. 关于ABAQUS2020二次开发
  13. 【线上直播ING】2016互联网金融应用发展半年报
  14. vue3 + TypeScript + vant +pinia 实现网易云音乐播放器
  15. python 数据处理之使用get_dummies进行one-hot编码
  16. vue及rect面试点(更新中) - 面试篇
  17. C语言之运算符练习题
  18. 7.4 反编译、篡改漏洞检测和重现
  19. google translate 插件修改可用地址
  20. Karl Guttag:Magic Leap 2与HoloLens 2对比

热门文章

  1. 基于Dubbo框架构建分布式服务(三)
  2. CSS3中弹性盒布局的最新版
  3. python 异常处理模块_扩展Python模块系列(五)----异常和错误处理
  4. Smarty目录结构和子目录路径问题
  5. day5学python 基础+装饰器内容
  6. 11. IDEA 在同一工作空间创建多个项目
  7. 使用badboy录制脚本 结合Jmeter一起测试。
  8. hdu-5781 ATM Mechine(dp+概率期望)
  9. hibernate中的id特殊属性hilo剖解(多用于继承关系)
  10. Log4net数据表