1. RBAC模型简介
1.1. RBAC三要素
RBAC权限模型(Role-Based Access Control:基于角色的访问控制)有3个基础组成部分,分别是:用户、角色和权限。它们之间的关系如下图所示:
- 用户(User):每个用户都有唯一的UID识别,并被授予不同的角色
- 角色(Role):不同角色具有不同的权限
- 权限(Permission):访问权限
- 用户-角色映射(user-role):用户和角色之间的映射关系
- 角色-权限映射(role-permission):角色和权限之间的映射关系
1.2. RBAC模型简介
把权限赋予角色,再把角色赋予用户。用户和角色,角色和权限都是多对多的关系。用户拥有的权限等于他所有的角色持有权限之和。(RBAC模型有多种变体,这里是最基础的base模型,其他如RBAC1,RBAC2等请参考 文档)
RBAC权限模型举例:管理员和普通用户两个角色被授予不同的权限:
- 普通用户只能去修改和查看个人信息,而不能创建用户和冻结用户,
- 管理员由于被授予所有权限,所以可以做所有操作
1.3. RBAC模型设计
这里 用户 与 角色 实体对应关系为多对多,角色与权限对应关系同样为多对多关系,所以在实体设计上用户与角色间增加<用户-角色>实体,将多对多的对应关系拆分为一对多。同理,角色与权限多对多对应关系拆分出中间实体对象<角色-权限>实体。
从上面实体对应关系分析,权限表设计分为以下基本的五张表结构:用户表(user),角色表(role),用户角色关系表(user_role),权限表(permission),角色权限关系表(role_permission),表结构关系如下:
2. 带租户隔离的RBAC模型
2.1. 需求场景:
一个公司有多个部门,各部门主管只能管理自己的部门,公司的CEO有操作所有部门的权限。
2.2. 实现方式
基于RBAC权限模型,在 user-role关系表里加上一个作用域范围(object_type和object_id)即可实现上述需求:
以上述场景为例,各用户对应的角色关系配置如下:
- object_type =DEPT:表示作用域为部门;object_id=deptA 即只能访问A部门
- object_type=GLOBEL: 表示作用域为全局,即可访问所有部门; object_id=-1 全局权限的特殊值表示
user-role | |||
user_id | role_id | object_type | object_id |
A部门主管 | 管理员 | DEPT | deptA |
A部门员工1 | 普通用户 | DEPT | deptA |
A部门员工2 | 普通用户 | DEPT | deptA |
B部门主管 | 管理员 | DEPT | deptB |
B部门员工1 | 普通用户 | DEPT | deptB |
B部门员工2 | 普通用户 | DEPT | deptB |
公司CEO | 超级管理员 | GLOBEL | -1 |
这样A部门主管的操作权限范围仅在部门A范围内,与B部门租户隔离,CEO有超级管理员权限,可以访问所有部门。
有了object_type和object_id就可以方便的扩展用户的访问权限范围。比如公司新起一个xx项目,只允许项目组员工访问,可以新增一个object_type=PROJECT来控制。
2.3. 后续优化
分析上面的角色类型,有两种类型:
- 全局角色(超级管理员),没有作用域限制,能访问全公司所有部门
- 受限角色(管理员/普通用户等),有作用域限制,只能访问指定部门
可以考虑将角色类型加入到 role表,便于快速判断角色的作用域范围:
role | |||
code | name | description | type |
super.manager | 超级管理员 | 全局管理员 | global |
dept.manager | 管理员 | 部门的主管 | scope |
dept.employee | 普通用户 | 部门的普通员工 | scope |
project.member | 项目组成员 | 项目组的成员 | scope |
完整的数据模型如下: