最近接触了一个 RBAC 权限管理系统的需求,将 RBAC 模型做一个总结。
在介绍 RBAC 之前,先说一下最简单最基础的权限控制模型,ACL 模型。
访问控制列表(ACL : Access Control List)
ACL 即控制访问列表,它规定了资源可以被哪些用户进行操作。
在 ACL 模型下,权限管理是围绕“资源”来设定的,用户是直接与资源相关联的。
资源:一般来说,可以是某个页面,也可以是某个 URI
那么进行配置时,需要维护一个表,即“访问控制列表”,这个表中需要描述出“资源-用户”之间的关系,比如:
id | resource | user_id |
---|---|---|
1 | /test1 | 10000 |
2 | /test2 | 10001 |
3 | /test1 | 10002 |
4 | /test3 | 10002 |
上面的表只是一种 ACL 的表现形式,能够描述出“资源-用户”之间的关系的表结构都可以作为一个 ACL 表。
- 在用户请求某个资源时,需要先进行权限校验,在访问控制列表中查询是否有此资源与用户的对应关系,再返回用户是否拥有访问权限。
- 上表我配置了三个 uri 资源,三个用户,其中 10002 用户拥有 /test1,/test3 两个资源的请求权限。
这种权限管理模型的好处就是简单,方便,适合数据量小,数据相对静态的情况,比较容易维护。
缺点也比较明显,当资源和用户量大起来的时候,不便于权限管理,试想有这么一种场景:存在多个用户拥有多个关联的访问权限,那么在新增一个用户时,需要给这个用户配置指定多个权限,新增一个关联资源或修改某个资源时,需要为所有分配了这个资源的用户修改,麻烦。
什么叫关联的访问权限?
比如一个系统中,新增往往伴随着编辑,那么这两个权限需要一起分配给用户。再比如某产品部门的所有人需要拥有自己产品的所有权限。
什么是 RBAC ?
Role-Based Access Control,即,基于角色的权限控制。在这个模型中,用户不直接与权限相关联,而是通过角色关联用户与权限,角色是用户和权限之间的桥梁。
相比较 ACL 模式,这样的好处是扩展性强,对于权限的管理更加方便了,在上面我们提到的问题中,可以直接为用户赋予角色,或者修改时仅维护角色中的权限,无需维护每个用户下的权限。这种模式适用于用户数量、权限数量多的平台。
RBAC 又分为四类:RBAC0,RBAC1,RBAC2,RBAC3,其中 RBAC0 是最基础最简单的,其余皆为在 RBAC0 之上的升级。
RBAC0 模型
其实这种模型就是我们上面提到的,用户、角色、权限的多对多关系。
在进行权限判断时,容易出现一种错误的实现方式,就是通过用户角色来判断用户执行权限,例如涨薪权限配置在 hr 角色下,在实现权限判断时,判断用户是否拥有 hr 角色。
1 | if user.hasRole("hr") { |
这样的做法是错误的,如果后面需要让主管角色也有调薪权限,那么就该修改源代码了,麻烦不?正确做法应该是:先查询用户所拥有的角色,再根据角色查询用户拥有的权限,最后判断用户是否拥有某个的权限。
RBAC1 模型
RBAC1 模型又可以叫做“角色继承的 RBAC 模型”,引入了角色的继承概念,即角色具有上下级的关系,子角色可以继承父角色的所有权限。
角色继承的种类又分两种:
一般继承关系:要求角色继承关系是一个绝对偏序关系,允许角色间的多继承
受限继承关系:进一步要求角色继承关系是一个树结构,实现角色间的单继承
这里我本人不太理解的一点是,不清楚角色之间的继承实现,网络上其他文章讲到这里也比较含糊不清,或者有多种说法。
一种说法是,权限小的角色继承权限大的角色,即权限大的角色是父角色,权限小的角色是子角色,是为了防止出现权限分配失误,子角色拥有父角色所没有的权限,所以子角色继承父角色的权限,只能在父角色权限下进行删减。
另一种说法相反,权限大的角色继承权限小的角色,即权限小的角色是父角色,权限大的角色是子角,例如一个公司中,主管是拥有员工所持有的权限的,所以主管继承员工的权限,不需要再手动为主管角色配置基础的员工权限,只要配置主管独有的权限即可。
两种说法都有其道理,可以看做是 RBAC1 的两个不同实现方式吧,根据需求来选用。
RBAC2 模型
RBAC2 模型又可以叫“约束控制的 RBAC 模型”,增加了对角色的一些限制:
- 互斥角色:互斥角色指权限相互制约的两个角色,同一用户只能分配到一组互斥角色中至多一个角色。比如运动员和裁判。案例:一个人不能既是运动员又是裁判。
- 基数约束:一个角色被分配的用户数量受限,一个用户可拥有的角色数量受限,一个角色对应的访问权限数量受限。案例:某角色比较重要,比如超级管理员角色,需要规定角色数量防止重要权限泄露。
- 先觉条件角色:用户想获得某上级角色,必须先获得其下一级角色。案例:先拥有副总经理权限,才能拥有总经理权限。
- 运行时互斥:例如,允许一个用户具有两个角色的成员资格,但在运行中不可同时激活这两个角色,案例:同一个用户拥有多个角色,角色的权限有重叠,以较大权限为准。
上面的约束也可以叫做“责任分离”,责任分离包括静态责任分离和动态责任分离。
- 静态责任分离:用户无法同时被赋予互斥的角色
- 动态责任分离,用户可以被授予互斥的角色,但在一次会话中不能同时激活自身拥有的互斥的角色
RBAC3 模型
又被称为“统一模型”,它包含了 RBAC1 和 RBAC2 的特性,既有角色分层又有角色约束。
其他
RBAC 模型不是一成不变的,上述几种只是较为常见的,它也可以有更多的实现方式,只要是基于“用户-角色-权限”这套思想实现的,都可以称之为 RBAC 模型,在实际使用中要根据需求来决定,比如 RBAC1 中两种不同的角色继承方式的实现。下面还有一些其他的类型。
用户组
如果熟悉 linux 的同学,应该知道 linux 系统有用户和用户组的概念,也一定熟悉在使用 ll 命令或 chmod 命令为文件设置权限。见下图(请忽略它是个 mac 系统)
这里你大概就懂了,用户组的作用就是包含多个用户,只需要为用户组配置角色,就不用为这些用户单独配置角色了,进一步方便了权限的管理。比如新建一个开发者用户组,为开发者用户组配置了某些角色,将开发者添加进开发者用户组,所有开发者用户都会获得该用户组下的数据权限
用户组的形式也是多样的,除了上面提到的这种,更常见的是作为“组织”,比如总公司与分公司,不同地区的分公司组织拥有不同的角色权限,也可以是作为“职位”,不同职位的员工拥有不同的角色权限。