AppBox 是基於 FineUI 的通用權限管理框架,包括用戶管理、職稱管理、部門管理、角色管理、角色權限管理等模塊。php
AppBox v2.0中權限管理中涉及三個概念:模塊、用戶、角色html
1. 權限是定義在模塊中,而模塊至關於一個分組,好比用戶管理就是一個模塊。用戶分組模塊能夠包含的多個頁面,好比用戶列表頁面、新增用戶頁面、修改用戶頁面、用戶詳細信息查看頁面、修改用戶密碼頁面等;sql
2. 角色擁有對權限的控制,能夠設置一個角色擁有哪些權限;數據庫
3. 一個用戶能夠有多個角色,用戶最終的權限來本身所屬角色的權限集合。框架
下面看一下在AppBox v2.0中設置角色權限的頁面:數據庫設計
經過上面的描述能夠看出,「模塊」在整個權限設計中並不重要,僅僅至關於權限的一個分組。post
「模塊」的引入使得系統看起來更加複雜,好比判斷一個用戶對某個頁面是否有瀏覽權限?ui
明顯角色模塊權限表的設計會比較複雜,由於每一個模塊的權限個數不一樣,能夠須要特殊的結構。url
在AppBox v2.0中,咱們是經過JSON結構保持除瀏覽權限以外的全部權限。來看下數據庫表X_RoleModule的初始化腳本:spa
SET IDENTITY_INSERT [dbo].[X_RoleModule] ON INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (311, 1, N'CoreUser', 1, N'{"New":true,"Edit":true,"Delete":true,"ChangePassword":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (312, 1, N'CoreRoleUser', 1, N'{"New":true,"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (313, 1, N'CoreRoleModule', 1, N'{"Edit":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (314, 1, N'CoreRole', 1, N'{"New":true,"Edit":true,"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (315, 1, N'CorePassword', 1, N'{"Edit":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (316, 1, N'CoreOnlineUser', 1, N'') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (317, 1, N'CoreMenu', 1, N'{"New":true,"Edit":true,"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (318, 1, N'CoreLog', 1, N'{"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (319, 1, N'CoreJobTitle', 1, N'{"New":true,"Edit":true,"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (320, 1, N'CoreDept', 1, N'{"New":true,"Edit":true,"Delete":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (321, 1, N'CoreConf', 1, N'{"Edit":true}') INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (322, 1, N'AppFile', 1, N'')
這種複雜性不只在數據庫設計階段,在代碼編寫階段也不大好處理,須要大量的代碼維護權限列表的讀寫操做。
下面的代碼是更新角色對應的模塊權限列表的後臺代碼:
FineUI.CheckBoxField canReadField = Grid2.FindColumn("CanRead") as FineUI.CheckBoxField; XRoleModuleCollection roleModules = new XRoleModuleCollection(); foreach (GridRow row in Grid2.Rows) { int rowIndex = row.RowIndex; object[] dataKeys = Grid2.DataKeys[rowIndex]; // 當前行對應的模塊名稱 //int moduleId = Convert.ToInt32(dataKeys[0]); string moduleName = dataKeys[1].ToString(); bool canRead = canReadField.GetCheckedState(rowIndex); AspNet.CheckBoxList ddlOthers = (AspNet.CheckBoxList)Grid2.Rows[rowIndex].FindControl("ddlOthers"); JObject otherPowerObj = new JObject(); foreach (AspNet.ListItem item in ddlOthers.Items) { if (item.Selected) { otherPowerObj.Add(item.Value, true); } } if (canRead || otherPowerObj.Count > 0) { XRoleModule roleModule = new XRoleModule(); roleModule.RoleId = roleId; roleModule.ModuleName = moduleName; roleModule.CanRead = canRead; if (otherPowerObj.Count > 0) { roleModule.Others = otherPowerObj.ToString(Newtonsoft.Json.Formatting.None); } else { roleModule.Others = ""; } roleModules.Add(roleModule); } } roleModules.BatchSave();
在這段代碼中,咱們不只須要更新瀏覽權限,還須要將其餘權限生成JSON字符串,並插入數據庫。
此外因爲咱們還要維護菜單列表,在菜單和模塊的關係上用戶也產生了疑問,來看下編輯菜單的頁面截圖。
用戶須要進一步地瞭解以下概念:
1. 一個模塊能夠對應多個頁面;
2. 一個頁面能夠是菜單項,也能夠不是菜單項;
3. 須要指定一個菜單項所屬的模塊,以便根據權限定義生成左側菜單項。
我不清楚這個概念以前是否有人提過,不過這是獨立思考的結果,所以我就給他起了個響亮的名字 - 「扁平化的權限設計」。
之因此是扁平化,是由於咱們捨棄了「模塊」的頁面,因此的權限(在其餘系統中可能稱之爲功能點)均可以單獨定義,而每一個頁面只須要在這個很大的權限集合中選中本身須要的權限子集(一般,在實踐中這個過程是相反的:也便是每一個頁面定義本身須要的權限集合,全部頁面的權限集合造成了整個站點的權限集合)。
扁平化的權限設計示意圖:
數據庫設計簡單,天然代碼就簡單了。前面足足 40 多行的保存權限的代碼,如今不用 20 行就實現了:
// 當前角色新的權限列表 List<int> newPowerIDs = new List<int>(); for (int i = 0; i < Grid2.Rows.Count; i++) { AspNet.CheckBoxList ddlPowers = (AspNet.CheckBoxList)Grid2.Rows[i].FindControl("ddlPowers"); foreach (AspNet.ListItem item in ddlPowers.Items) { if (item.Selected) { newPowerIDs.Add(Convert.ToInt32(item.Value)); } } } Role role = DB.Roles.Include(r => r.Powers).Where(r => r.ID == roleId).FirstOrDefault(); ReplaceEntities<Power>(role.Powers, newPowerIDs.ToArray()); DB.SaveChanges();
爲了不權限集合過於分散,咱們還爲每一個權限定義了 GroupName (分組屬性),從而在前臺展現時更美觀,更簡潔。
權限表的模型類:
public class Power { [Key] public int ID { get; set; } [Required, StringLength(50)] public string Name { get; set; } [StringLength(50)] public string GroupName { get; set; } [StringLength(200)] public string Title { get; set; } [StringLength(500)] public string Remark { get; set; } public virtual ICollection<Role> Roles { get; set; } }
保存角色權限的頁面截圖:
雖然界面和以前的差很少,但內部實現已經簡化了不少。
菜單項編輯時,只須要指定菜單項對應的瀏覽權限便可(若是不指定瀏覽權限,則默認這個菜單項不參與權限控制),以下圖所示。
1. AppBox v2.0 是免費軟件,免費提供下載:http://fineui.com/bbs/forum.php?mod=viewthread&tid=3788
2. AppBox v3.0 是捐贈軟件,你能夠經過捐贈做者來獲取AppBox v3.0的所有源代碼(http://fineui.com/donate/)。
喜歡這篇文章,請幫忙點擊頁面右下角的【推薦】按鈕。
感謝各位網友的支持,本文再次榮登【10天推薦排行榜】第一名,上一次登上第一名是:#CSDN刷票門# 有沒有人在惡意刷票?CSDN請告訴我!用24小時監控數聽說話!
此活動已結束,不會再單獨發送PDF文件。
《AppBox升級進行時》前 7 篇文章已經所有在博客公開,請你們直接在個人博客上瀏覽。後面的文章還沒開始寫。