AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理、职称管理、部门管理、角色管理、角色权限管理等模块。

AppBox v2.0中的权限实现

AppBox v2.0中权限管理中涉及三个概念:模块、用户、角色

1. 权限是定义在模块中,而模块相当于一个分组,比如用户管理就是一个模块。用户分组模块可以包含的多个页面,比如用户列表页面、新增用户页面、修改用户页面、用户详细信息查看页面、修改用户密码页面等;

2. 角色拥有对权限的控制,可以设置一个角色拥有哪些权限;

3. 一个用户可以有多个角色,用户最终的权限来自己所属角色的权限集合。

下面看一下在AppBox v2.0中设置角色权限的页面:

通过上面的描述可以看出,“模块”在整个权限设计中并不重要,仅仅相当于权限的一个分组。

为什么说AppBox v2.0中的模块是鸡肋!

“模块”的引入使得系统看起来更加复杂,比如判断一个用户对某个页面是否有浏览权限?

明显角色模块权限表的设计会比较复杂,因为每个模块的权限个数不同,可以需要特殊的结构。

在AppBox v2.0中,我们是通过JSON结构保持除浏览权限之外的所有权限。来看下数据库表X_RoleModule的初始化脚本:

  1. SET IDENTITY_INSERT [dbo].[X_RoleModule] ON
  2. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (311, 1, N'CoreUser', 1, N'{"New":true,"Edit":true,"Delete":true,"ChangePassword":true}')
  3. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (312, 1, N'CoreRoleUser', 1, N'{"New":true,"Delete":true}')
  4. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (313, 1, N'CoreRoleModule', 1, N'{"Edit":true}')
  5. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (314, 1, N'CoreRole', 1, N'{"New":true,"Edit":true,"Delete":true}')
  6. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (315, 1, N'CorePassword', 1, N'{"Edit":true}')
  7. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (316, 1, N'CoreOnlineUser', 1, N'')
  8. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (317, 1, N'CoreMenu', 1, N'{"New":true,"Edit":true,"Delete":true}')
  9. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (318, 1, N'CoreLog', 1, N'{"Delete":true}')
  10. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (319, 1, N'CoreJobTitle', 1, N'{"New":true,"Edit":true,"Delete":true}')
  11. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (320, 1, N'CoreDept', 1, N'{"New":true,"Edit":true,"Delete":true}')
  12. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (321, 1, N'CoreConf', 1, N'{"Edit":true}')
  13. INSERT [dbo].[X_RoleModule] ([Id], [RoleId], [ModuleName], [CanRead], [Others]) VALUES (322, 1, N'AppFile', 1, N'')

这种复杂性不仅在数据库设计阶段,在代码编写阶段也不大好处理,需要大量的代码维护权限列表的读写操作。

下面的代码是更新角色对应的模块权限列表的后台代码:

  1. FineUI.CheckBoxField canReadField = Grid2.FindColumn("CanRead") as FineUI.CheckBoxField;
  2. XRoleModuleCollection roleModules = new XRoleModuleCollection();
  3. foreach (GridRow row in Grid2.Rows)
  4. {
  5. int rowIndex = row.RowIndex;
  6.  
  7. object[] dataKeys = Grid2.DataKeys[rowIndex];
  8. // 当前行对应的模块名称
  9. //int moduleId = Convert.ToInt32(dataKeys[0]);
  10. string moduleName = dataKeys[1].ToString();
  11.  
  12. bool canRead = canReadField.GetCheckedState(rowIndex);
  13. AspNet.CheckBoxList ddlOthers = (AspNet.CheckBoxList)Grid2.Rows[rowIndex].FindControl("ddlOthers");
  14.  
  15. JObject otherPowerObj = new JObject();
  16. foreach (AspNet.ListItem item in ddlOthers.Items)
  17. {
  18. if (item.Selected)
  19. {
  20. otherPowerObj.Add(item.Value, true);
  21. }
  22. }
  23.  
  24. if (canRead || otherPowerObj.Count > 0)
  25. {
  26. XRoleModule roleModule = new XRoleModule();
  27. roleModule.RoleId = roleId;
  28. roleModule.ModuleName = moduleName;
  29.  
  30. roleModule.CanRead = canRead;
  31. if (otherPowerObj.Count > 0)
  32. {
  33. roleModule.Others = otherPowerObj.ToString(Newtonsoft.Json.Formatting.None);
  34. }
  35. else
  36. {
  37. roleModule.Others = "";
  38. }
  39.  
  40. roleModules.Add(roleModule);
  41. }
  42. }
  43. roleModules.BatchSave();

在这段代码中,我们不仅需要更新浏览权限,还需要将其他权限生成JSON字符串,并插入数据库。  

此外由于我们还要维护菜单列表,在菜单和模块的关系上用户也产生了疑问,来看下编辑菜单的页面截图。

用户需要进一步地了解如下概念:

1. 一个模块可以对应多个页面;

2. 一个页面可以是菜单项,也可以不是菜单项;

3. 需要指定一个菜单项所属的模块,以便根据权限定义生成左侧菜单项。

AppBox v3.0全新的“扁平化权限设计”! 

我不清楚这个概念之前是否有人提过,不过这是独立思考的结果,因此我就给他起了个响亮的名字 - “扁平化的权限设计”。

之所以是扁平化,是因为我们舍弃了“模块”的页面,所以的权限(在其他系统中可能称之为功能点)都可以单独定义,而每个页面只需要在这个很大的权限集合中选中自己需要的权限子集(通常,在实践中这个过程是相反的:也即是每个页面定义自己需要的权限集合,所有页面的权限集合形成了整个站点的权限集合)。

扁平化的权限设计示意图:

数据库设计简单,自然代码就简单了。前面足足 40 多行的保存权限的代码,现在不用 20 行就实现了:

  1. // 当前角色新的权限列表
  2. List<int> newPowerIDs = new List<int>();
  3. for (int i = 0; i < Grid2.Rows.Count; i++)
  4. {
  5. AspNet.CheckBoxList ddlPowers = (AspNet.CheckBoxList)Grid2.Rows[i].FindControl("ddlPowers");
  6. foreach (AspNet.ListItem item in ddlPowers.Items)
  7. {
  8. if (item.Selected)
  9. {
  10. newPowerIDs.Add(Convert.ToInt32(item.Value));
  11. }
  12. }
  13. }
  14.  
  15. Role role = DB.Roles.Include(r => r.Powers).Where(r => r.ID == roleId).FirstOrDefault();
  16. ReplaceEntities<Power>(role.Powers, newPowerIDs.ToArray());
  17.  
  18. DB.SaveChanges();

为了避免权限集合过于分散,我们还为每个权限定义了 GroupName (分组属性),从而在前台展示时更美观,更简洁。

权限表的模型类:

  1. public class Power
  2. {
  3. [Key]
  4. public int ID { get; set; }
  5.  
  6. [Required, StringLength(50)]
  7. public string Name { get; set; }
  8.  
  9. [StringLength(50)]
  10. public string GroupName { get; set; }
  11.  
  12. [StringLength(200)]
  13. public string Title { get; set; }
  14.  
  15. [StringLength(500)]
  16. public string Remark { get; set; }
  17.  
  18. public virtual ICollection<Role> Roles { get; set; }
  19.  
  20. }

保存角色权限的页面截图:

  

虽然界面和之前的差不多,但内部实现已经简化了很多。

菜单项编辑时,只需要指定菜单项对应的浏览权限即可(如果不指定浏览权限,则默认这个菜单项不参与权限控制),如下图所示。

下载或捐赠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/)。

返回《AppBox升级进行时》目录

喜欢这篇文章,请帮忙点击页面右下角的【推荐】按钮。

后记

感谢各位网友的支持,本文再次荣登【10天推荐排行榜】第一名,上一次登上第一名是:#CSDN刷票门# 有没有人在恶意刷票?CSDN请告诉我!用24小时监控数据说话!

此活动已结束,不会再单独发送PDF文件。

《AppBox升级进行时》前 7 篇文章已经全部在博客公开,请大家直接在我的博客上浏览。后面的文章还没开始写。

AppBox升级进行时 - 扁平化的权限设计的更多相关文章

  1. AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...

  2. AppBox升级进行时 - Entity Framework的增删改查

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework新增数据 以新增用户为例,作为对比,先来看下使 ...

  3. AppBox升级进行时 - 关联表查询与更新(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...

  4. AppBox升级进行时 - Attach陷阱(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Attach方法 前面我们已经多次使用Attach方法,上一次使用Attach ...

  5. AppBox升级进行时 - 如何向OrderBy传递字符串参数(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework提供的排序功能 再来回顾一下上篇文章,加载用户 ...

  6. AppBox升级进行时 - Any与All的用法(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 属于某个角色的用户列表(Any的用法) 使用Subsonic,我们有两种方法获 ...

  7. docker跨主机通信扁平化网络的设计与实现

    端口映射.ovs. fannel,weave 1.使用网桥实现跨主机容器连接 使用Open vSwitch实现跨主机容器连接

  8. 扁平化设计的最新趋势 – 长阴影(Long Shadow)

    随着互联网的发展,网页设计变得越来越复杂,如今设计的外观和感觉实现网站功能说使用的开发技术一样重要.互联网的功能远远不只是基本的信息共享,现在人们对网站的期望是远远大于几年前的. 如今,HTML5 & ...

  9. Flatty Shadow图标自动产生器——在线生成各种扁平化 ICON

    在扁平化风格越来越流行的今天,网页.软件界面和图标的设计大都采用了扁平化风格.特别是扁平化图标的设计,摒弃了一切3D元素的设计,阴影.纹理.透视神马的统统不要,让图标简洁高效,富有现代感. 今天给大家 ...

随机推荐

  1. 钉钉js依赖库学习

    看别人用的依赖库的好处在于,你知道有什么可以用,什么可以借鉴.(钉钉——协作桌面应用) PS:人最怕是不知道,而不是你不会. 1. jQuery 钉钉使用了1.9.1版本的jQuery,jQuery作 ...

  2. 天津政府应急系统之GIS一张图(arcgis api for flex)讲解(十二)水情雨情模块

    config.xml文件的配置如下: <widget label="水情" icon="assets/images/water.png" config=& ...

  3. Angular+Grunt+Bower+Karma+Protractor (Atom)

    1. 配置bower 1.安装bower npm install -g bower 2.创建.bowerrc文件 { "directory": "src/bower&qu ...

  4. iOS中的交换空间(swap space)

    看来是没有交换空间,原因是闪存和SSD硬盘相比,速度很慢,也有电源管理的原因. the NAND flash is not designed to be used as swap. It is dam ...

  5. 谈谈AppDelegate

    谈谈AppDelegate 前言 每个iOS程序都会有一个AppDelegate的类,这个类就是一个代理类,我们新建一个Project的时候,里面都会带有这个类.现在就让我们看看这个类. 开始介绍 对 ...

  6. iOS 疑难杂症 — — 在 Storyboard 里 Add Size Class Customization 后再从代码里无法修改的问题

    前言 公司的产品同时适配 iPhone 和 iPad ,并坚持用 Storyboard 来做适配,今天又踩一个坑(以前遇到过)还以为是 XCode 的鬼毛病. 声明  欢迎转载,但请保留文章原始出处: ...

  7. python-切片 迭代 生成器

    1 切片操作 >>> L ['aaa', 'bbb', 'ccc', 'ddd'] >>> L[0:3] ['aaa', 'bbb', 'ccc'] >> ...

  8. js中A包含B的写法与分割字符串的方法

    在java中A包含B的写法 if(A.contains(B)){ ... } 在js中没有contains方法,应该使用下面这种方法: var an = "传染性.潜伏性.破坏性" ...

  9. RMAN还原遭遇ORA-32006&ORA-27102错误

    案例环境:   服务器A: 操作系统 : Red Hat Enterprise Linux ES release 4 (Nahant Update 6) 数据库版本: Oracle Database ...

  10. SQL Server跨库查询

    方式一: 语句 SELECT * FROM 数据库A.dbo.表A a, 数据库B.dbo.表B b WHERE a.field=b.field "DBO"可以省略 如 SELEC ...