ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
![](https://img.kancloud.cn/0e/5d/0e5d1d6b3d67706dba5940814dd5406c_503x294.png) ![](https://img.kancloud.cn/31/c3/31c387d34624679901395e9ca01186e0_1176x649.png) ![](https://img.kancloud.cn/f5/50/f5500813d5887f168bb71e22b0afbc5b_1165x684.png) ![](https://img.kancloud.cn/11/80/11808a36acd0d770e84b67709971f778_1237x563.png) ![](https://img.kancloud.cn/8e/fc/8efc618c0b88fe5ecd28b19b3b21e23e_1201x558.png) ![](https://img.kancloud.cn/31/3a/313a8814d8cdf035b529360049a404dc_519x300.png) ![](https://img.kancloud.cn/75/b0/75b0bda6a5a6e4acf39640ef936e3548_964x433.png) 模型中权限这个元素,按颗粒度从大到小,可以分为: * 导航:由路由控制,是否可以访问一组页面 * 页面:是否可以访问某个页面 * 操作:访问某个页面时,按钮是否可以见,可否增删改查 * 字段:页面中某个字段是否可见、是否可编辑 如果员工没有某对象“查看列表”的权限,则该对象的功能入口会被隐藏 如果员工没有某对象的操作点权限,则在对象页面上隐藏相应操作按钮 如果员工没有某对象的指定字段的可见权限,则在对象页面上隐藏相应字段 同理如果权限较多时也会存在一样的问题,处理方式是引入权限组的概念,将使用场景相对固定的一组功能或权限打包成组赋予角色。但是一般来讲一个系统中权限功能的体量是相对有限和可控的,所以实际应用中对权限组的使用较少。 ![](https://img.kancloud.cn/b3/ad/b3adc71f1b50235c404eabfe27ea69c8_935x552.png) **3\. 角色继承的RBAC模型** 在一个业务场景中,如果角色需区分:设计主管、设计组长、设计成员,并且管理方式为向下兼容时,则需使用角色继承的 RBAC 模型。上层角色继承下层角色的全部权限,且可额外赋予权限。 ![](https://img.kancloud.cn/90/fe/90fe6bd6d21274aa9b65ba8803c40a8c_385x419.png) 此时除了对角色进行定义,还需要管理角色间的关系,通过关系来体现角色的层级关系,从而达到继承权限的效果。角色的继承关系主要有两种:树形图和有向无环图。 ![](https://img.kancloud.cn/f6/cd/f6cdab1f60dac5dfc4838f533c69991a_974x330.png) 继承关系常常来源于公司团队的组织结构,此时常将角色与组织结构进行关联达到继承角色模型的效果。如下图所示的赵同学,其角色是「三级团队负责人」,与其并列的小组中有多个「三级团队负责人」的角色,但依附于左侧的组织结构树,各级负责人仅有查看和操作自己下属子节点的权限。 ![](https://img.kancloud.cn/3e/8e/3e8e30784d9f7845480cf7003d4151e7_1003x556.png) **4\. 限制的RBAC模型** 在一个产品或系统中,部分角色可能是需要隔离的、不允许被同时赋予一个人的。跟大家熟知的不能既是「运动员」又是「裁判员」一个道理。 因此,对于众多角色中的一组,只能是单选的关系,但多组角色之间可以共同存在。如下图中,一个用户可以既为设计师又为管理员,但在设计师角色组中仅能被赋予一个角色,在管理员角色组中也仅能被赋予一个角色。 ![](https://img.kancloud.cn/ad/28/ad2820e5cd5110f79d5215ca38e1ccf6_588x422.png) 此外,限制还有可能是数量上的,比如一个产品组中必须有且只有一个管理员,不允许删除或再分配管理员角色,仅允许将负责人角色变更。 ![](https://img.kancloud.cn/e8/24/e824827583c56b6d686e4c18617cb9e7_999x300.png) 限制的模型不仅仅对分配过程产生影响,有时即使拥有了多种角色,因为不同的角色对同一个功能的使用方式或数据会产生冲突,所以使用时也需要进行限制。如下图所示为同一时间仅允许以一个身份登录。 ![](https://img.kancloud.cn/dd/d9/ddd92cc33fa4b8fb3a389702f7eeca2e_524x467.png) 根据不同的业务需求,限制的形式很多。需要注意的是不能仅依赖后端限制,而是要在前端展示清晰的规则和恰当的限制,避免用户出错和沮丧。 #### 三、权限的拆分与设计 通过 RBAC 模型已经能够很好的搭建起用户、角色与权限之间的关系了。但具体是什么样的关系,以及「权限」这个抽象的概念具体如何规划? 这些都需要分析清楚才能进一步设计出完善的权限系统。 首先需要知道,一般产品的权限由页面、操作和数据构成。页面与操作相互关联,必须拥有页面权限,才能分配该页面下对应的操作权限。数据可被增删改查。 整体关系如下图所示: ![](https://img.kancloud.cn/d3/9a/d39a4e8184a10012ed9702e685a70573_916x556.png) 因此,在设计之初我们就需要考虑到未来可能区分角色的地方,尽量解耦、模块化。对于技术来说,每一个页面模块、每一个操作都最好使用独立的接口。对于设计来说,需要保障所有角色因为权限而屏蔽掉部分操作和数据后,页面和流程仍能体验流畅。 保证初期设计支持后,配置权限时,还需要注意以下几点: **1\. 确定是否支持前端配置** 如果角色和权限相对固定,则一般将角色与权限的关系可以写在后台,改动时需要后端变更且重新上线。这种情况适用于公司内部系统等只有一个使用主体的系统。 如果需要自定义角色或者每个角色在不同使用者的场景下有不同的权限,则需要将角色的定义、角色与权限之间的配置体现在「前端用户配置页面」。这种情况适用于有频繁变动的自定义角色权限,和有租户体系的系统。 **2\. 以基本单元拆分,以业务逻辑配置** 一般可将每个对象的「增、删、改、查」各自作为一个基本的权限单元。打个比方,在「人员管理」中,查看人员列表、添加人员、删除人员、编辑人员信息最好拆分为4个权限单元。在技术和设计上,我们希望能尽量做到解耦和模块化。 但是在业务层面有些操作却是一体的。这些不能拆开的权限在「前端用户配置页面」中建议打包成一个整体提供配置。例如:如果我们确定在系统的现有和未来业务中,仅分为普通成员有「人员管理」的查看权限,管理员有操作权限,则可将「增、删、改」三个基本权限单位合并为「操作」权限进行配置。 **3\. 页面权限优先于操作和数据权限** 必须配置了页面模块权限后,才能配置当前页面模块下具体的操作权限,以及页面模块的数据展示权限。 **4\. 查看权限优先于增删改权限** 正常情况下,一定要先能查看某个模块或操作,其它的增删改操作才有意义。因此在设计时,应在获取查看权限前限制其它权限的配置,或者配置其它权限时默认赋予查看权限。 **5\. 角色与权限的多种关系** 角色与权限的关系不仅是单纯「是/否关系」,还包括以某种限制进行操作,和以某种程度访问数据。 例如在「人员管理」中: * 数据范围:用户拥有查看人员列表的权限,但仅能查看自己所在的团队; * 数据边界限制(上限等):添加人员时不能超过20个等。 * 数据字段:HR 能查看人员列表中包括职级、薪资等字段,其它角色仅能查看姓名邮箱等字段; **6\. 角色与权限的设计表达** 在传达一个系统的权限设计规则时,设计师常常习惯用主观最直接的方式表达想法,如用「当……时,就……」的句式来表达。但一个平台中涉及的权限规则是非常多的,当通篇以这样的形式描述时,表达对象将很难理解。 正确的描述方式:更清晰的是基于开发的语言,和技术模型的结果进行表达。将各角色与权限单元绘制成网格,每个交叉点网格中描述该角色与权限的数据关系和限制。 如下图所示: ![](https://img.kancloud.cn/40/f8/40f8beb178770570916dac29d8f977a4_1080x548.png) #### 四、需要注意的Tips **1\. 隐形的admin** 在可自定义角色和权限的系统中,一般需要预留一个 admin 角色来进行系统的初始配置,用于添加首批的业务人员和配置基本的角色。 有的系统中允许存在上帝视角的 admin 角色,则其可以作为「超级管理员」显示在角色配置的列表中。有的系统中不允许这种角色存在,则可将这种角色设置为隐形的状态,仅赋予维护系统的工作人员。 **2\. 初始权限的赋予** 对于允许用户自行加入的系统,需要设定一至多个默认的角色,有时可以是仅有最基础权限的「游客」角色。 初始权限还可以与用户既有的某些数据字段进行关联,如添加用户时获取到用户的岗位为「设计师」,则直接赋予「设计师」角色的权限。 **3\. 人员管理中对自己的处理** 在人员管理中,管理员角色处理自己时需要额外注意。因为如果修改或删除了自己角色后,可能导致系统没有管理角色,从而无法添加其他成员和正常运行。设计时可添加判断,当自己为唯一管理角色时,禁止编辑和删除。 **4\. 无页面权限的提示** 虽然可以通过页面权限限制直接隐藏当前用户没有权限的页面,但不能排除用户获取到权限外的 url 地址。当用户意外访问到没有权限的页面时务必提供「无权限」的提示,避免用户认为系统 bug。 #### 总结 总结一下,整个权限系统设计就是定义各个节点和节点间关系的过程。 节点包括: * 用户; * 用户组; * 角色; * 角色组; * 权限(页面、操作、数据); * 权限组(页面、操作、数据)。 关系包括: * 是/否关系; * 继承关系; * 限制关系(互斥、范围限制、边界限制、字段限制……); 梳理清楚所有逻辑后,通过灵活定义节点和组合各节点之间的关系,便能够轻松完成角色权限设计的100种解法。 例子:   先大概解释下我们的业务,我们做的是教育行业高校云平台,每个学校都可以在我们平台进行注册,注册完成后可以享受一些基础的服务,当然了不同级别的用户享受的基础服务是不同的,这些基础的服务包括新生注册管理、基础系统管理、考试系统管理、评教系统管理等模块,每个模块都相当于一个子系统,每个子系统都有各自的功能,每个功能也都有各自的相关的页面,而所有的子系统、页面以及页面上的功能按钮都是需要我们权限进行管理,所以我们的权限管理相对来说任务也是比较繁重的。     我们先来看下我们权限管理模块的类图: ![](https://img.kancloud.cn/fa/0b/fa0b21547f4599870bed5ee67d77bee3_792x487.png) 用户组是垂直的概念,相当于部门和人的关系。公司-->部门-->人,至上而下;这个部门只能做这个部门的事情; 角色是水平的概念,相当于是等级的划分。CEO-->VP-->部门经理-->项目经理-->员工;例如每个经理都可以打考勤考核工资等等,拥有共同的权限。 当需要单独设置的时候,就需要针对某个用户进行设置了。 核心还是基于用户、角色和许可的RBAC模型,只不过我们将这三者分别进行了相应的扩展: ## 用户     无论哪个用户首先它必须是属于某个部门的,部门是行政单位,而某个部门也可以包含多个用户,所以部门和用户的关系为1对多的关系;     先说一下为什么要有用户组的概念,如果有一类的用户都要属于某个角色,我们一个个给用户授予角色,重复工作特别多,所以我们把这么一些用户进行分类,也就是用户组,这样的话,我们直接对用户组赋予角色,减少重复的工作量,这样达到的目的是这,用户拥有的所有许可,就是用户个人所属角色拥有的许可与该用户所在用户组所属角色拥有的许可之和。一个用户可以属于多个用户组,一个用户组也可以包括多个用户,所以用户与用户组是多对多的关系; ## 角色     角色是一定数量的许可的集合,许可的载体,一个角色可以包含多个用户,一个用户同样的也可以属于多个角色,所以角色与用户的关系为多对多的关系。同样的一个角色可以包含多个用户组,一个用户组也可以属于多个角色,所以角色和用户组也是多对多的关系; ## 许可     许可我一般称它为权限,它包括控制对象和操作,控制对象一般为资源,包括菜单、页面、文件等资源,而操作一般包括增删改查等,图中“系统操作”就是操作,“菜单信息”就是控制对象;     菜单信息中的每个菜单都会有增删改查等操作,所以菜单信息与系统操作是一对多的关系;     我们给角色授予权限时,授予就是颗粒最小的权限,所以我们将系统操作权限授予某些角色。一个角色可以拥有多个系统操作,一个系统操作同样也可以属于多个角色,所以系统操作和角色为多对多的关系。     到这里我们就将我们的权限模型之间的关系基本上介绍完毕了,在类图中的两个类之间的多对多的关系在数据库中会出现第三张表,所以下面我们来看下我们的数据库中表的关系图: ![](https://img.kancloud.cn/98/c7/98c76f61b284cafa59c4fcefb0be20ac_619x739.png) # 四、改进     现在这个权限模型已经开发出来投入使用了,当然了现在的模型也不一定是最好的,只能说针对于现在的系统的规模是比较合适的,对于现在的权限模型还是有可以扩展的地方,其实就是类图中的菜单信息,在系统中我们只是粗犷的将子系统名称、子系统菜单、子系统菜单页面元素、文件等这些资源全部放到了一个表中即菜单信息表,在表中我们利用类型进行具体区分,同时利用上下级关系来管理他们之间的层次关系,但是在这个表中冗余的数据会特别多,我觉得如果可以更进一步改善的话,可以考虑将菜单表按照菜单类型进行拆分,然后再来一张表资源关系表来管理这些类型资源之间的关系。 ![](https://img.kancloud.cn/97/95/97956150cbd7957e54d820bb7571ed44_507x410.png) ![](https://img.kancloud.cn/8c/3f/8c3fcc13666339ef9f67a5d70e537a53_576x768.png)