.NET Core微服務 權限系統+工作流(一)權限系統


一、前言

實際上權限系統老早之前我就在一直開發,大概在剛畢業沒多久就想一個人寫一個系統,斷斷續續一直堅持到現在,畢竟自己親動手自寫的系統才有收獲,本篇僅介紹權限。

  小小系統上不了台面,望各位大神勿噴。

二、系統介紹

目前采用的是.Net Core微服務的方式實現,本文不討論具體的中間件主要是(ocelot + consul等),一直參考微軟的  eShopOnContainers ,進行簡單的實現,但是ORM是用的Dapper,並簡單進行封裝  傳送門 ,當然自己也封裝了一些簡單的插件進行復用:傳送門,如下:

三、權限系統

權限系統實現很簡單,權限的划分我覺得可以分為三種:

1、菜單權限2、按鈕權限3、數據權限

簡單介紹下:1、菜單權限。表示用戶是否能夠訪問該頁面(角色掛鈎)

      2、按鈕權限。表示用戶是否能夠操作該頁面上的功能(角色掛鈎)

      3、數據權限。表示用戶訪問頁面時進行數據篩選(該功能暫未實現,這個要與具體的業務結合才能寫),與部門掛鈎,這個不太好理解,當然一般的權限系統這個功能也不會做,舉個簡單例子,OA系統里面我查看我的工資條,我應該只能看到我自己的數據,但是我的部門經理,他可以有權限看到該部門的全部數據,這個就是數據權限。

為什么寫這個系統?

  之前待過好幾家公司,發現他們的系統都是對菜單進行分配,當然了,業務需求只要這個就當我沒說,我只是覺得這樣做太不安全並且我覺得之前系統的實現方式可以進行一些優化,所以就一直寫到現在,可能代碼質量不如哪些大神的優秀,系統在我看來太小,就簡單搭了個框架實現。你過條小水溝,沒必要造條橋。

要使用該系統前提條件:前端:Sea.js和Vue,對於sea.js,在前端這塊感覺已經沒多少人用了,但是這中CMD思想是不會被淘汰的,你看最近比較火的layerui也是的,對於Vues只是簡單的應用,也就用到雙向綁定而已,開發復雜的頁面確實比較方便,但是簡單的頁面就得不償失了。

           后端:consul、rabbitmq ,具體怎么安裝不在描述

大概的用戶訪問流程描述如下:

用戶登錄      =====》  獲取該用戶角色   ===》  通過角色獲取該角色對應的權限 並集  ===>返回相應數據

      sys_user_role      sys_role_resource

 

系統關系圖如下(MySQL):

 

具體功能實現請看代碼,這里不做闡述,菜單權限的分配通過角色表和菜單表的關聯表操作即可,但是按鈕的權限分配如何實現?我的實現方式是:把按鈕的操作也看成一種菜單的資源分配,只不過比較特殊,我這里不僅僅是對按鈕的顯示進行控制,我做的比較絕,也對后台方法訪問權限也做了控制,這樣比較安全,對於按鈕權限的控制,實際上是明確的,比方說,一個刪除按鈕,它只能對應后台的一個刪除方法,這個方法是明確的,對於頁面的按鈕的類型和個數是固定的,不然你沒辦法分配,基於這個前提,我對菜單的生成進行代碼控制從而達到控制目的,因此,菜單和按鈕和在一起稱之為資源表 sys_resource 。具體的實現代碼也不是很復雜,一層一層判斷即可,權限過濾器如下:

  1     public class PermissionAuthorizationRequirement : IAuthorizationRequirement
  2     {
  3         public UrlAndButtonType UrlAndButtonType { get; }
  4 
  5         public PermissionAuthorizationRequirement(string url, ButtonType buttonType, bool isPage)
  6         {
  7             UrlAndButtonType = new UrlAndButtonType()
  8             {
  9                 Url = url,
 10                 ButtonType = (byte)buttonType,
 11                 IsPage = isPage
 12             };
 13         }
 14         public PermissionAuthorizationRequirement(string url, byte buttonType, bool isPage)
 15         {
 16             UrlAndButtonType = new UrlAndButtonType()
 17             {
 18                 Url = url,
 19                 ButtonType = buttonType,
 20                 IsPage = isPage
 21             };
 22         }
 23     }
 24     /// <summary>
 25     /// 權限過濾器
 26     /// </summary>
 27     [Authorize]
 28     [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
 29     public sealed class PermissionAttribute : TypeFilterAttribute
 30     {
 31         /// <summary>
 32         /// 構造器
 33         /// </summary>
 34         /// <param name="url">地址</param>
 35         /// <param name="buttonType">按鈕類型</param>
 36         /// <param name="isPage">是否是頁面</param>
 37         public PermissionAttribute(string url = default(string), ButtonType buttonType = ButtonType.View, bool isPage = true) :
 38             base(typeof(RequiresPermissionAttributeExecutor))
 39         {
 40             Arguments = new object[] { new PermissionAuthorizationRequirement(url, buttonType, isPage) };
 41         }
 42         /// <summary>
 43         /// 構造器
 44         /// </summary>
 45         /// <param name="url">地址</param>
 46         /// <param name="buttonType">按鈕類型</param>
 47         /// <param name="isPage">是否是頁面</param>
 48         public PermissionAttribute(string url, byte buttonType, bool isPage = true) :
 49             base(typeof(RequiresPermissionAttributeExecutor))
 50         {
 51             Arguments = new object[] { new PermissionAuthorizationRequirement(url, buttonType, isPage) };
 52         }
 53 
 54         private class RequiresPermissionAttributeExecutor : Attribute, IAsyncResourceFilter
 55         {
 56             private IPermissionStorageContainer _permissionStorage;
 57             private PermissionAuthorizationRequirement _requiredPermissions;
 58 
 59             public RequiresPermissionAttributeExecutor(
 60                 IPermissionStorageContainer permissionStorage, PermissionAuthorizationRequirement requiredPermissions)
 61             {
 62                 _permissionStorage = permissionStorage;
 63                 _requiredPermissions = requiredPermissions;
 64             }
 65 
 66             public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
 67             {
 68                 string menuUrl = _requiredPermissions.UrlAndButtonType.Url;
 69                 //判斷用戶權限
 70                 if (string.IsNullOrEmpty(menuUrl))
 71                 {
 72                     //區域判斷
 73                     string area = context.RouteData.Values["area"].ToString();
 74                     if (string.IsNullOrEmpty(area))
 75                     {
 76                         menuUrl = "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"];
 77                     }
 78                     else
 79                     {
 80                         menuUrl = "/" + area + "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"];
 81                     }
 82                 }
 83                 menuUrl = menuUrl.Trim().ToLower();
 84                 var dbpermission = await _permissionStorage.GetPermissionAsync();
 85                 var menu = dbpermission.Menus.FirstOrDefault(m => m.MenuUrl != null && m.MenuUrl.Trim().ToLower() == menuUrl);
 86                 if (menu != null)//地址存在
 87                 {
 88                     if (_requiredPermissions.UrlAndButtonType.ButtonType == default(byte))
 89                     {
 90                         await next();
 91                     }
 92                     else
 93                     {
 94                         byte buttonType = (byte)_requiredPermissions.UrlAndButtonType.ButtonType;
 95                         if (menu.MenuButton.Select(m => m.ButtonType).Contains(buttonType))//擁有操作權限
 96                         {
 97                             await next();
 98                         }
 99                         else
100                         {
101                             //沒有操作權限
102                             if (_requiredPermissions.UrlAndButtonType.IsPage)
103                             {
104                                 context.Result = new RedirectResult("/error/noauth");
105                             }
106                             else
107                             {
108                                 context.Result = new ContentResult()
109                                 {
110                                     Content = PermissionStatusCodes.Status2Unauthorized.ToString()
111                                 };
112                             }
113                             await context.Result.ExecuteResultAsync(context);
114                         }
115                     }
116                 }
117                 else
118                 {
119                     //沒有操作權限
120                     if (_requiredPermissions.UrlAndButtonType.IsPage)
121                     {
122                         context.Result = new RedirectResult("/error/noauth");
123                     }
124                     else
125                     {
126                         context.Result = new ContentResult()
127                         {
128                             Content = PermissionStatusCodes.Status2Unauthorized.ToString()
129                         };
130                     }
131                     await context.Result.ExecuteResultAsync(context);
132                 }
133             }
134         }
135 
136     }

在對於的頁面添加過濾器即可,如下:

 1         [HttpGet]
 2         [Permission]
 3         public async Task<IActionResult> Index(int pageIndex=1,int pageSize=10)
 4         {
 5             var res = await _messageService.GetPageAsync(pageIndex, pageSize);
 6             return View(res);
 7         }
 8         [HttpGet]
 9         [Permission("/Sys/Message/Index", ButtonType.View)]
10         public IActionResult Show()
11         {
12             return View();
13         }

 系統界面展示圖:后台模板是之前從網上找的並自己簡單改了一下,將就能看吧,實在不想花功夫在前端上面了@-^-@

運行步驟:1、確保數據庫mssystem和mssystemlog存在 github文檔中

     2、consul服務啟動,如下回車運行

     3、VS項目啟動

管理員登錄賬號wms,密碼:所有賬號密碼都是123

代碼地址:

https://github.com/wangmaosheng/MsSystem-BPM-ServiceAndWebApps

如果覺得有點作用的話,可以 start 下,后續會持續更新


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM