大部分系统都会有权限模块,别人家系统的权限怎么生成的我不知道,我只知道这样做是可以并且挺好的。

文章中只对asp.net core的部分代码进行说明 呃 记录~,mvc版本自行前往仓库查阅

代码中的一些特性标记后面列出,或前往仓库查看~

1.根据特性标记生成模块权限

先上效果图,感兴趣的前往Demo仓库地址,不感兴趣的关闭页面吧~

模型定义

Demo中菜单分为三级,首先使用枚举定义模块,FirstModuleMenu为一级菜单,SecondModuleMenu为二级菜单,三级菜单在action方法上由PermissionDescription标识并IsMenu=true的方法

若是页面功能则为IsMenu=false

可使用的特性标记还包含以下几种,并且权限验证时依次递增:

  • 免登录:AllowAnonymous
  • 管理员默认权限: NonePermissionAttribute
  • 指定权限: PermissionDescriptionAttribute
  • 依赖权限(包含有这些的任一权限都将获得授权): ParentPermissionAttribute
  1. //一级菜单
  2. public class FirstModuleMenu
  3. {
  4. public const string 系统管理 = "系统|icon-setting";
  5. public const string 用户管理 = "用户|icon-user";
  6. }
  7. //二级菜单
  8. public enum SecondModuleMenu
  9. {
  10. [Description(FirstModuleMenu.系统管理)]
  11. 系统设置,
  12. [Description(FirstModuleMenu.用户管理)]
  13. 用户管理,
  14. }
  15. //三级菜单
  16. [PermissionDescription(SecondModuleMenu.系统设置, "站点设置", true)]
  17. public ActionResult SiteSetting()
  18. {
  19. return Content("站点设置 System/SiteSetting");
  20. }

生成权限模型集合

定义权限模型 SysModule.cs

调用初始化权限方法

  1. private static List<SysModule> _AllAdminModule { get; set; } = new List<SysModule>();
  2. /// <summary>
  3. /// 初始化权限
  4. /// </summary>
  5. public static void InitPermission()
  6. {
  7. var result = new List<SysModule>();
  8. #region 通过反射读取Action方法写入对应权限至集合
  9. //读取CoreDemo程序集中集成自AdminController的控制器
  10. var types = Assembly.Load("CoreDemo").GetTypes().Where(e => e.BaseType.Name == nameof(AdminController));
  11. var area = "";//默认未使用区域
  12. var now = DateTime.Now;
  13. var i = 1;
  14. foreach (var type in types)
  15. {
  16. //获取所有action方法
  17. var members = type.GetMethods().Where(e => e.ReturnType.Name == nameof(ActionResult) || e.ReturnType.Name == nameof(IActionResult));
  18. foreach (var member in members)
  19. {
  20. //获取功能列表
  21. var attrs = member.GetCustomAttributes(typeof(PermissionDescriptionAttribute), true);
  22. if (attrs.Length == 0)
  23. continue;
  24. //功能对应的二级菜单
  25. var parentMenuEnum = (attrs[0] as PermissionDescriptionAttribute).ParentMenu;
  26. var parentMenuName = parentMenuEnum.ToString();
  27. //功能对应的一级菜单 名称|icon类名
  28. var enumArry = parentMenuEnum.GetEnumDescription().Split('|');
  29. var mainMenuName = enumArry[0];
  30. var existMainMenu = result.Where(e => e.ModuleName == mainMenuName).FirstOrDefault();
  31. if (existMainMenu == null)
  32. {
  33. var mainMenu = new SysModule()
  34. {
  35. Id = i,
  36. ParentId = 0,
  37. ModuleName = mainMenuName,
  38. Icon = enumArry[1] ?? "",
  39. Area = area,
  40. Controller=string.Empty,
  41. Action=string.Empty,
  42. IsMenu = true,
  43. IsVisible = true,
  44. Remark = string.Empty,
  45. DisplayOrder = i,
  46. CreateTime = now
  47. };
  48. i++;
  49. existMainMenu = mainMenu;
  50. existMainMenu.Children = new List<SysModule>();
  51. //添加一级菜单
  52. result.Add(existMainMenu);
  53. }
  54. var existParentMenu = existMainMenu.Children.Where(e => e.ModuleName == parentMenuName).FirstOrDefault();
  55. if (existParentMenu == null)
  56. {
  57. var parentMenu = new SysModule()
  58. {
  59. Id = i,
  60. ParentId = existMainMenu.Id,
  61. ModuleName = parentMenuName,
  62. Icon=string.Empty,
  63. Area = area,
  64. Controller = string.Empty,
  65. Action = string.Empty,
  66. IsMenu = enumArry.Length != 3 || bool.Parse(enumArry[2]),
  67. IsVisible = true,
  68. DisplayOrder = i,
  69. CreateTime = now,
  70. Children = new List<SysModule>()
  71. };
  72. i++;
  73. existParentMenu = parentMenu;
  74. existParentMenu.Children = new List<SysModule>();
  75. existMainMenu.Children.Add(existParentMenu);
  76. //添加二级菜单
  77. result.Add(existParentMenu);
  78. }
  79. var menu = new SysModule()
  80. {
  81. Id = i,
  82. ParentId = existParentMenu.Id,
  83. Area = area,
  84. Action = member.Name,
  85. DisplayOrder = i,
  86. CreateTime = now,
  87. Controller = member.DeclaringType.Name.Substring(0, member.DeclaringType.Name.Length - 10),
  88. IsMenu = (attrs[0] as PermissionDescriptionAttribute).IsMenu,
  89. Children = new List<SysModule>(),
  90. };
  91. if (menu.IsMenu)
  92. menu.IsVisible = true;
  93. menu.ModuleName = (attrs[0] as PermissionDescriptionAttribute).FuncName;
  94. i++;
  95. existParentMenu.Children.Add(menu);
  96. result.Add(menu);
  97. }
  98. }
  99. #endregion
  100. //todo 添加到数据库
  101. _AllAdminModule = result;
  102. }

2.使用过滤器拦截请求进行验证

新建特性标记 AdminAuthorizeAttribute 继承Attribute类以及实现IAuthorizationFilter接口的OnAuthorization方法

不多说,上图

不多说,上代码↓_↓

权限验证过滤器:AdminAuthorizeAttribute

  1. //后台权限验证
  2. public class AdminAuthorizeAttribute : Attribute,IAuthorizationFilter
  3. {
  4. public void OnAuthorization(AuthorizationFilterContext filterContext)
  5. {
  6. //匿名标识 无需验证
  7. if (filterContext.Filters.Any(e => (e as AllowAnonymous) != null))
  8. return;
  9. var adminInfo = GlobalContext.AdminInfo;//此处应为获取的登录用户
  10. if (adminInfo == null)
  11. {
  12. if(filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
  13. {
  14. filterContext.Result = new JsonResult("未登录");
  15. }
  16. else
  17. {
  18. filterContext.Result =new ContentResult() { Content = "未登录" };
  19. }
  20. return;
  21. }
  22. //对应action方法或者Controller上若存在NonePermissionAttribute标识,即表示为管理员的默认权限,只要登录就有权限
  23. var isNone = filterContext.Filters.Any(e => (e as NonePermissionAttribute) != null);
  24. if (isNone)
  25. return;
  26. //获取请求的区域,控制器,action名称
  27. var area = filterContext.RouteData.DataTokens["area"]?.ToString();
  28. var controller = filterContext.RouteData.Values["controller"]?.ToString();
  29. var action = filterContext.RouteData.Values["action"]?.ToString();
  30. var isPermit = false;
  31. //校验权限
  32. isPermit = ServiceFactory.CheckAdminPermit(adminInfo.Id, area, controller, action);
  33. if (isPermit)
  34. return;
  35. //此action方法的父辈权限判断,只要有此action对应的父辈权限,皆有权限访问
  36. var pAttrs = filterContext.Filters.Where(e => (e as ParentPermissionAttribute) != null).ToList();
  37. if (pAttrs.Count > 0)
  38. {
  39. foreach (ParentPermissionAttribute pattr in pAttrs)
  40. {
  41. if (!string.IsNullOrEmpty(pattr.Area))
  42. area = pattr.Area;
  43. isPermit = ServiceFactory.CheckAdminPermit(adminInfo.Id, area, pattr.Controller, pattr.Action);
  44. if (isPermit)
  45. return;
  46. }
  47. }
  48. if (!isPermit)
  49. {
  50. filterContext.Result = new ContentResult() { Content = "无权限访问" };
  51. return;
  52. }
  53. }
  54. }

自定义特性标记,用于权限校验

此处的自定义的特性标记不能继承Attribute,因无法在AdminAuthorizeAttribute中的上下文filterContext.Filters中获取到特性标记(不知道咋取特性标记,所以用这种方式代替,也更为简单 冏)

!!!!!!!!!修改: 之前脑袋没有转过弯来,要使过滤器上下文的Filters中发现自定义过滤器需要继承 Attribute, IFilterMetadata

  1. /// <summary>
  2. /// 管理员的默认权限
  3. /// </summary>
  4. public class NonePermissionAttribute : Attribute, IFilterMetadata{}
  5. /// <summary>
  6. /// 匿名验证
  7. /// </summary>
  8. public class AllowAnonymous : Attribute, IFilterMetadata{}
  9. /// <summary>
  10. /// 长辈权限
  11. /// </summary>
  12. [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
  13. public class ParentPermissionAttribute : Attribute, IFilterMetadata
  14. {
  15. /// <summary>
  16. /// 区域
  17. /// </summary>
  18. public string Area { get; set; }
  19. /// <summary>
  20. /// 控制器
  21. /// </summary>
  22. public string Controller { get; set; }
  23. /// <summary>
  24. /// Action名称
  25. /// </summary>
  26. public string Action { get; set; }
  27. public ParentPermissionAttribute(string area, string controller, string action)
  28. {
  29. this.Area = area;
  30. this.Controller = controller;
  31. this.Action = action;
  32. }
  33. public ParentPermissionAttribute(string controller, string action)
  34. {
  35. this.Controller = controller;
  36. this.Action = action;
  37. }
  38. }

若将代码全部贴出,有点略显多余,故,只贴出了部分核心代码.其他一些模型,扩展 请直奔仓库地址...

或使用git命令克隆MvcPermission分支到MvcPermission文件夹:git clone https://git.coding.net/yimocoding/WeDemo.git -b MvcPermission

补充

  • 2017-09-29

    突然灵光一现,将文中的ResultFilterAttribute特性标记替换为Attribute, IFilterMetadata ,果然可以~

    故得出:实现了IFilterMetadata的特性标记能够在过滤器的上下文中获取到。

asp.net core权限模块的快速构建的更多相关文章

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

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

  2. CZGL.Auth: ASP.NET Core Jwt角色授权快速配置库

    CZGL.Auth CZGL.Auth 是一个基于 Jwt 实现的快速角色授权库,ASP.Net Core 的 Identity 默认的授权是 Cookie.而 Jwt 授权只提供了基础实现和接口,需 ...

  3. asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用

    前言:由于公司占时没有运维,出于微服务的需要,Apollo只能先装在windows 阿里云上跑起来,由于环境及网络等问题,在安装过程中遇到很多坑,算是一个个坑填完后,最终实现. 一. java jdk ...

  4. 麻雀虽小,五脏俱全。基于Asp.net core + Sqlite 5分钟快速上手一个小项目

    虽然该方法不会用在实际开发中,但该过程对于初学者还是非常友好的,真应了麻雀虽小,五脏俱全这句话了.好了不多废话了,直接开始!! 1.建立一个名为test的Asp.net core web应用程序 这一 ...

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

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

  6. 使用 Asp.net core 2.0 + Angular 4 构建车辆管理的Web应用程序

    https://www.codeproject.com/Articles/1210559/Asp-net-core-Angular-Build-from-scratch-a-web

  7. c#、ASP.NET core 基础模块之一:linq(原创)

    最近做数据查询,发现linq 真的比我 印象中  要强大的多,实用的多,所以 我决定  要与linq  来一场  深入交流, 因为linq的基础用法 可以百度一大摞,我就记录点不一样的,结合我做项目使 ...

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

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...

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

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

随机推荐

  1. RPC服务不可用总结

    A简单方法: 通过"控制面板/管理工具/服务",检查一下RPC的Remote Procedure Call (RPC)和Remote Procedure Call (RPC) Lo ...

  2. 003-0.6632是float/Float/double/Double中的哪个?

    应该是float,最后两个是包装类,这里应该安装基本类型去看待. 而java的浮点型默认是double型,如果希望生成一个float型的浮点数则需要在这个值的后面紧跟f和F.

  3. 锋利的jQuery幻灯片实例

    //锋利的jQuery幻灯片实例 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  4. IEnumerable和IQueryable接口

    之间的区别 IQueryable继承于IEnumerable IEnumerable:IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等一些扩展方法之前数据就已经加 ...

  5. CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用

    作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...

  6. Linaro系统获取root权限方法

    在Zedboard上根据教程安装Linaro Ubuntu后出现一只无法获取Root权限,导致无法挂载U盘等问题. 具体体现在sudo -s命令之后,出现如sudo:must be setuid ro ...

  7. PyCharm:2017.3版即将新增科学计算模式,预览版现在可以下载使用

    编译:Lemon,原文作者:Ernst Haagsman 公众号:Python数据之道(ID:PyDataRoad) pycharm:2017.3版即将新增科学计算模式 在JetBrains将发布的新 ...

  8. Ubuntu 14.02 cmake升级 失败解决

    错误的提示: CMake Error: Could not find CMAKE_ROOT !!! CMake has most likely not been installed correctly ...

  9. 201521123059 《Java程序设计》第六周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  10. 201521123071 《JAVA程序设计》第十二周学习总结

    第12周作业-多线程 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件线程相关内容. 2. 书面作业 1. 字符流与文本文件:使用 PrintWriter(写),Buff ...