asp.net core权限模块的快速构建
大部分系统都会有权限模块,别人家系统的权限怎么生成的我不知道,我只知道这样做是可以并且挺好的。
文章中只对asp.net core
的部分代码进行说明 呃 记录~,mvc版本自行前往仓库查阅
代码中的一些特性标记后面列出,或前往仓库查看~
1.根据特性标记生成模块权限
先上效果图,感兴趣的前往Demo仓库地址,不感兴趣的关闭页面吧~
模型定义
Demo中菜单分为三级,首先使用枚举定义模块,FirstModuleMenu为一级菜单,SecondModuleMenu为二级菜单,三级菜单在action方法上由
PermissionDescription
标识并IsMenu=true
的方法
若是页面功能则为IsMenu=false
可使用的特性标记还包含以下几种,并且权限验证时依次递增:
- 免登录:
AllowAnonymous
- 管理员默认权限:
NonePermissionAttribute
- 指定权限:
PermissionDescriptionAttribute
- 依赖权限(包含有这些的任一权限都将获得授权):
ParentPermissionAttribute
//一级菜单public class FirstModuleMenu{public const string 系统管理 = "系统|icon-setting";public const string 用户管理 = "用户|icon-user";}//二级菜单public enum SecondModuleMenu{[Description(FirstModuleMenu.系统管理)]系统设置,[Description(FirstModuleMenu.用户管理)]用户管理,}//三级菜单[PermissionDescription(SecondModuleMenu.系统设置, "站点设置", true)]public ActionResult SiteSetting(){return Content("站点设置 System/SiteSetting");}
生成权限模型集合
定义权限模型 SysModule.cs
调用初始化权限方法
private static List<SysModule> _AllAdminModule { get; set; } = new List<SysModule>();/// <summary>/// 初始化权限/// </summary>public static void InitPermission(){var result = new List<SysModule>();#region 通过反射读取Action方法写入对应权限至集合//读取CoreDemo程序集中集成自AdminController的控制器var types = Assembly.Load("CoreDemo").GetTypes().Where(e => e.BaseType.Name == nameof(AdminController));var area = "";//默认未使用区域var now = DateTime.Now;var i = 1;foreach (var type in types){//获取所有action方法var members = type.GetMethods().Where(e => e.ReturnType.Name == nameof(ActionResult) || e.ReturnType.Name == nameof(IActionResult));foreach (var member in members){//获取功能列表var attrs = member.GetCustomAttributes(typeof(PermissionDescriptionAttribute), true);if (attrs.Length == 0)continue;//功能对应的二级菜单var parentMenuEnum = (attrs[0] as PermissionDescriptionAttribute).ParentMenu;var parentMenuName = parentMenuEnum.ToString();//功能对应的一级菜单 名称|icon类名var enumArry = parentMenuEnum.GetEnumDescription().Split('|');var mainMenuName = enumArry[0];var existMainMenu = result.Where(e => e.ModuleName == mainMenuName).FirstOrDefault();if (existMainMenu == null){var mainMenu = new SysModule(){Id = i,ParentId = 0,ModuleName = mainMenuName,Icon = enumArry[1] ?? "",Area = area,Controller=string.Empty,Action=string.Empty,IsMenu = true,IsVisible = true,Remark = string.Empty,DisplayOrder = i,CreateTime = now};i++;existMainMenu = mainMenu;existMainMenu.Children = new List<SysModule>();//添加一级菜单result.Add(existMainMenu);}var existParentMenu = existMainMenu.Children.Where(e => e.ModuleName == parentMenuName).FirstOrDefault();if (existParentMenu == null){var parentMenu = new SysModule(){Id = i,ParentId = existMainMenu.Id,ModuleName = parentMenuName,Icon=string.Empty,Area = area,Controller = string.Empty,Action = string.Empty,IsMenu = enumArry.Length != 3 || bool.Parse(enumArry[2]),IsVisible = true,DisplayOrder = i,CreateTime = now,Children = new List<SysModule>()};i++;existParentMenu = parentMenu;existParentMenu.Children = new List<SysModule>();existMainMenu.Children.Add(existParentMenu);//添加二级菜单result.Add(existParentMenu);}var menu = new SysModule(){Id = i,ParentId = existParentMenu.Id,Area = area,Action = member.Name,DisplayOrder = i,CreateTime = now,Controller = member.DeclaringType.Name.Substring(0, member.DeclaringType.Name.Length - 10),IsMenu = (attrs[0] as PermissionDescriptionAttribute).IsMenu,Children = new List<SysModule>(),};if (menu.IsMenu)menu.IsVisible = true;menu.ModuleName = (attrs[0] as PermissionDescriptionAttribute).FuncName;i++;existParentMenu.Children.Add(menu);result.Add(menu);}}#endregion//todo 添加到数据库_AllAdminModule = result;}
2.使用过滤器拦截请求进行验证
新建特性标记
AdminAuthorizeAttribute
继承Attribute
类以及实现IAuthorizationFilter
接口的OnAuthorization
方法
不多说,上图
不多说,上代码↓_↓
权限验证过滤器:AdminAuthorizeAttribute
//后台权限验证public class AdminAuthorizeAttribute : Attribute,IAuthorizationFilter{public void OnAuthorization(AuthorizationFilterContext filterContext){//匿名标识 无需验证if (filterContext.Filters.Any(e => (e as AllowAnonymous) != null))return;var adminInfo = GlobalContext.AdminInfo;//此处应为获取的登录用户if (adminInfo == null){if(filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest"){filterContext.Result = new JsonResult("未登录");}else{filterContext.Result =new ContentResult() { Content = "未登录" };}return;}//对应action方法或者Controller上若存在NonePermissionAttribute标识,即表示为管理员的默认权限,只要登录就有权限var isNone = filterContext.Filters.Any(e => (e as NonePermissionAttribute) != null);if (isNone)return;//获取请求的区域,控制器,action名称var area = filterContext.RouteData.DataTokens["area"]?.ToString();var controller = filterContext.RouteData.Values["controller"]?.ToString();var action = filterContext.RouteData.Values["action"]?.ToString();var isPermit = false;//校验权限isPermit = ServiceFactory.CheckAdminPermit(adminInfo.Id, area, controller, action);if (isPermit)return;//此action方法的父辈权限判断,只要有此action对应的父辈权限,皆有权限访问var pAttrs = filterContext.Filters.Where(e => (e as ParentPermissionAttribute) != null).ToList();if (pAttrs.Count > 0){foreach (ParentPermissionAttribute pattr in pAttrs){if (!string.IsNullOrEmpty(pattr.Area))area = pattr.Area;isPermit = ServiceFactory.CheckAdminPermit(adminInfo.Id, area, pattr.Controller, pattr.Action);if (isPermit)return;}}if (!isPermit){filterContext.Result = new ContentResult() { Content = "无权限访问" };return;}}}
自定义特性标记,用于权限校验
此处的自定义的特性标记不能继承Attribute
,因无法在AdminAuthorizeAttribute中的上下文filterContext.Filters
中获取到特性标记(不知道咋取特性标记,所以用这种方式代替,也更为简单 冏)
!!!!!!!!!修改: 之前脑袋没有转过弯来,要使过滤器上下文的Filters中发现自定义过滤器需要继承 Attribute, IFilterMetadata
/// <summary>/// 管理员的默认权限/// </summary>public class NonePermissionAttribute : Attribute, IFilterMetadata{}/// <summary>/// 匿名验证/// </summary>public class AllowAnonymous : Attribute, IFilterMetadata{}/// <summary>/// 长辈权限/// </summary>[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]public class ParentPermissionAttribute : Attribute, IFilterMetadata{/// <summary>/// 区域/// </summary>public string Area { get; set; }/// <summary>/// 控制器/// </summary>public string Controller { get; set; }/// <summary>/// Action名称/// </summary>public string Action { get; set; }public ParentPermissionAttribute(string area, string controller, string action){this.Area = area;this.Controller = controller;this.Action = action;}public ParentPermissionAttribute(string controller, string action){this.Controller = controller;this.Action = action;}}
若将代码全部贴出,有点略显多余,故,只贴出了部分核心代码.其他一些模型,扩展 请直奔仓库地址...
或使用git命令克隆MvcPermission
分支到MvcPermission文件夹:git clone https://git.coding.net/yimocoding/WeDemo.git -b MvcPermission
补充
- 2017-09-29
突然灵光一现,将文中的ResultFilterAttribute
特性标记替换为Attribute, IFilterMetadata
,果然可以~
故得出:实现了IFilterMetadata
的特性标记能够在过滤器的上下文中获取到。
转载于:https://www.cnblogs.com/morang/p/7606843.html
asp.net core权限模块的快速构建相关推荐
- 在ASP.NET Core中使用Apworks快速开发数据服务
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支 ...
- ASP.NET Core 3.0 实战:构建多版本 API 接口
第一次在博客写分享,请多多捧场,如有歧义请多多包含! 因为业务需求发展需要,所以API接口的变更升级是必不可少的事情,而原有的接口是不可能马上停止使用的.例如:Login接口为例,1.0版本之返回用户 ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新手朋友),但是转念一想不如来点猛的(考虑到急性子的朋友),让你通过本文的学习就能快速的入门ASP.NET Core.既 ...
- ASP.NET Core WebApi构建API接口服务实战演练
一.ASP.NET Core WebApi课程介绍 人生苦短,我用.NET Core!提到Api接口,一般会想到以前用到的WebService和WCF服务,这三个技术都是用来创建服务接口,只不过Web ...
- 使用ASP.NET Core 3.x 构建 RESTful API - 1. 开始
以前写过ASP.NET Core 2.x的REST API文章,今年再更新一下到3.0版本. 预备知识:ASP.NET Core 和 C# 工具:Visual Studio 2019最新版(VSCod ...
- 如何测试ASP.NET Core Web API
在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...
- asp.net core 系列 18 web服务器实现
一. ASP.NET Core Module 在介绍ASP.NET Core Web实现之前,先来了解下ASP.NET Core Module.该模块是插入 IIS 管道的本机 IIS 模块(本机是指 ...
- [翻译] ASP.NET Core 2.2 正式版发布
本文为翻译,原文地址:https://blogs.msdn.microsoft.com/webdev/2018/12/04/asp-net-core-2-2-available-today/ 我(文章 ...
- 如何测试 ASP.NET Core Web API
在本文中,我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案.我们将了解使用单元测试进行内部测试,使用全新的 ASP .NET Core 的集成测试框架来进行外部测试 ...
最新文章
- java 的lambda表达式
- python turtle什么意思_Python turtle shape和
- 知识点讲解一:代理ip中的proxies
- POJ - 3254 Corn Fields(状压dp)
- RxJava学习-使用篇
- MySQL 修改数据
- SQL 数据表基本操作
- OpenCV下载/OpenCV国内镜像/opencv_contrib下载
- ORB SLAM 2 demo 复现
- crmeb重新安装_CRMEB系统安装访问不了
- 【信息系统项目管理师】第十三章 项目合同管理思维导图
- 面试时应该问公司一些什么问题?
- 计算机WIN7安装,教您win7旗舰版安装教程
- SpringBoot整合Shiro学习(上)
- Python 中文(大写)数字转阿拉伯数字
- Lightweight Augmented Graph Network Hashing for Scalable Image Retrieval
- 期货交易应该如何界定交易中的时间周期?
- primocache学生党常用场景设置
- Thinkphp5使用phpword生成图表
- c++ 字符串流 sstream(常用于格式转换)
热门文章
- golang mysql断线_MySQL的连接池、异步、断线重连-Go语言中文社区
- Vue项目中 css样式的作用域(深度作用选择器)
- LeetCode 345. 反转字符串中的元音字母
- python--从入门到实践--chapter 9 类
- 怎样从php转向java_Github标星10.8K!Java 实战博客项目分享
- python rsa 公钥解密_python使用rsa库做公钥解密(网上别处找不到)
- pythonmain是什么意思_Python中if __name__ == __main__详细解释
- mysql怎么多表备份_学习MySQL多表操作和备份处理
- 全面系统地总结Linux的基本操作(上)
- python中的深浅拷贝