大部分系统都会有权限模块,别人家系统的权限怎么生成的我不知道,我只知道这样做是可以并且挺好的。
文章中只对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权限模块的快速构建相关推荐

  1. 在ASP.NET Core中使用Apworks快速开发数据服务

    不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支 ...

  2. ASP.NET Core 3.0 实战:构建多版本 API 接口

    第一次在博客写分享,请多多捧场,如有歧义请多多包含! 因为业务需求发展需要,所以API接口的变更升级是必不可少的事情,而原有的接口是不可能马上停止使用的.例如:Login接口为例,1.0版本之返回用户 ...

  3. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新手朋友),但是转念一想不如来点猛的(考虑到急性子的朋友),让你通过本文的学习就能快速的入门ASP.NET Core.既 ...

  4. ASP.NET Core WebApi构建API接口服务实战演练

    一.ASP.NET Core WebApi课程介绍 人生苦短,我用.NET Core!提到Api接口,一般会想到以前用到的WebService和WCF服务,这三个技术都是用来创建服务接口,只不过Web ...

  5. 使用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 ...

  6. 如何测试ASP.NET Core Web API

    在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...

  7. asp.net core 系列 18 web服务器实现

    一. ASP.NET Core Module 在介绍ASP.NET Core Web实现之前,先来了解下ASP.NET Core Module.该模块是插入 IIS 管道的本机 IIS 模块(本机是指 ...

  8. [翻译] ASP.NET Core 2.2 正式版发布

    本文为翻译,原文地址:https://blogs.msdn.microsoft.com/webdev/2018/12/04/asp-net-core-2-2-available-today/ 我(文章 ...

  9. 如何测试 ASP.NET Core Web API

    在本文中,我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案.我们将了解使用单元测试进行内部测试,使用全新的 ASP .NET Core 的集成测试框架来进行外部测试 ...

最新文章

  1. java 的lambda表达式
  2. python turtle什么意思_Python turtle shape和
  3. 知识点讲解一:代理ip中的proxies
  4. POJ - 3254 Corn Fields(状压dp)
  5. RxJava学习-使用篇
  6. MySQL 修改数据
  7. SQL 数据表基本操作
  8. OpenCV下载/OpenCV国内镜像/opencv_contrib下载
  9. ORB SLAM 2 demo 复现
  10. crmeb重新安装_CRMEB系统安装访问不了
  11. 【信息系统项目管理师】第十三章 项目合同管理思维导图
  12. 面试时应该问公司一些什么问题?
  13. 计算机WIN7安装,教您win7旗舰版安装教程
  14. SpringBoot整合Shiro学习(上)
  15. Python 中文(大写)数字转阿拉伯数字
  16. Lightweight Augmented Graph Network Hashing for Scalable Image Retrieval
  17. 期货交易应该如何界定交易中的时间周期?
  18. primocache学生党常用场景设置
  19. Thinkphp5使用phpword生成图表
  20. c++ 字符串流 sstream(常用于格式转换)

热门文章

  1. golang mysql断线_MySQL的连接池、异步、断线重连-Go语言中文社区
  2. Vue项目中 css样式的作用域(深度作用选择器)
  3. LeetCode 345. 反转字符串中的元音字母
  4. python--从入门到实践--chapter 9 类
  5. 怎样从php转向java_Github标星10.8K!Java 实战博客项目分享
  6. python rsa 公钥解密_python使用rsa库做公钥解密(网上别处找不到)
  7. pythonmain是什么意思_Python中if __name__ == __main__详细解释
  8. mysql怎么多表备份_学习MySQL多表操作和备份处理
  9. 全面系统地总结Linux的基本操作(上)
  10. python中的深浅拷贝