AppBox 是基于 FineUI 的通用權限管理框架,包括用戶管理、職稱管理、部門管理、角色管理、角色權限管理等模塊。
AppBox v2.0中的權限實現
AppBox v2.0中權限管理中涉及三個概念:模塊、用戶、角色
1. 權限是定義在模塊中,而模塊相當于一個分組,比如用戶管理就是一個模塊。用戶分組模塊可以包含的多個頁面,比如用戶列表頁面、新增用戶頁面、修改用戶頁面、用戶詳細信息查看頁面、修改用戶密碼頁面等;
2. 角色擁有對權限的控制,可以設置一個角色擁有哪些權限;
3. 一個用戶可以有多個角色,用戶最終的權限來自己所屬角色的權限集合。
下面看一下在AppBox v2.0中設置角色權限的頁面:
通過上面的描述可以看出,“模塊”在整個權限設計中并不重要,僅僅相當于權限的一個分組。
為什么說AppBox v2.0中的模塊是雞肋!
“模塊”的引入使得系統看起來更加復雜,比如判斷一個用戶對某個頁面是否有瀏覽權限?
明顯角色模塊權限表的設計會比較復雜,因為每個模塊的權限個數不同,可以需要特殊的結構。
在AppBox v2.0中,我們是通過JSON結構保持除瀏覽權限之外的所有權限。來看下數據庫表X_RoleModule的初始化腳本:
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. 需要指定一個菜單項所屬的模塊,以便根據權限定義生成左側菜單項。
AppBox v3.0全新的“扁平化權限設計”!
我不清楚這個概念之前是否有人提過,不過這是獨立思考的結果,因此我就給他起了個響亮的名字 - “扁平化的權限設計”。
之所以是扁平化,是因為我們舍棄了“模塊”的頁面,所以的權限(在其他系統中可能稱之為功能點)都可以單獨定義,而每個頁面只需要在這個很大的權限集合中選中自己需要的權限子集(通常,在實踐中這個過程是相反的:也即是每個頁面定義自己需要的權限集合,所有頁面的權限集合形成了整個站點的權限集合)。
扁平化的權限設計示意圖:
數據庫設計簡單,自然代碼就簡單了。前面足足 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; } }
保存角色權限的頁面截圖:
雖然界面和之前的差不多,但內部實現已經簡化了很多。
菜單項編輯時,只需要指定菜單項對應的瀏覽權限即可(如果不指定瀏覽權限,則默認這個菜單項不參與權限控制),如下圖所示。
下載或捐贈AppBox
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 篇文章已經全部在博客公開,請大家直接在我的博客上瀏覽。后面的文章還沒開始寫。
文章列表