2. 权限模型设计:角色层次、权限粒度、角色继承与静态职责分离
权限模型这东西,说简单也简单,说复杂能让你改半年。我最早做权限系统时,以为弄个角色表、权限表就完事了。结果上线第一天,销售总监和运维总监的权限就打架了——俩人都是“总监”角色,但一个该看的合同数据另一个不该看。嗯,这就是典型的“角色层次没设计好”。
本章咱们就把这四个核心概念掰扯清楚:角色层次、权限粒度、角色继承、静态职责分离。别小看这四点,它们直接决定了你的系统能不能扛住企业级的多变场景。
2.1 角色层次:扁平还是树形?
角色层次解决的是“角色之间的关系怎么组织”。你想想看,公司里有CEO、总监、经理、员工,这些角色天然就有上下级关系。如果只做扁平的角色列表,那你每次分配权限都得给每个角色单独配一遍,累死人。
我做过的教训:有一回,客户要求给所有“部门经理”批量增加一个报表权限。如果是扁平结构,我得遍历所有经理角色,逐个更新。要是用了层次结构,我只需要在高层角色上加一次权限,下层自动继承。两种做法,工作量差了10倍。
常见的角色层次模型有三种:
| 模型类型 | 特点 | 适用场景 | 我的建议 |
|---|---|---|---|
| 扁平模型 | 角色无层级,每个角色独立配置 | 10个以内角色的小系统 | 不推荐,扩展性差 |
| 树形模型 | 角色有父子关系,子角色继承父角色的权限 | 大多数企业级应用 | 推荐,最常用 |
| 图模型 | 角色允许多继承,关系更灵活 | 复杂组织架构或跨部门场景 | 谨慎使用,管理成本高 |
我个人习惯选用树形模型。为什么?因为图模型虽然灵活,但你很难保证不出现循环继承——A继承B,B又继承A,权限解析时就炸了。树形模型无环,简单可靠。
2.2 权限粒度:粗还是细?
权限粒度指的是“一条权限控制到什么程度”。是控制到整个模块(比如“密钥管理”),还是控制到具体API(比如“POST /api/keys”),甚至是控制到某个字段(比如“只允许查看密钥的ID,不允许查看密钥值”)?
这里有个经典的权衡:
- 粗粒度:权限少,管理简单,但控制力弱。比如“密钥管理员”只有一个权限“所有密钥操作”。问题在于:你不能让某个人只负责创建密钥但无权删除。
- 细粒度:控制力强,但权限数量激增,配置工作量大。比如把每个CRUD操作都拆成独立权限,再加上字段级别的控制。
我的推荐方案是分层混搭:
- 服务级(最粗):控制某个角色是否能访问整个密钥服务。
- 资源级:控制对密钥、策略、审计日志等不同资源的访问。
- 操作级:控制Create、Read、Update、Delete等具体操作。
- 字段级(最细):控制某个资源下的敏感字段是否可见。
具体到密钥权限接口,我常用的粒度设计是:
# 权限标识命名规范
# 格式:{服务}:{资源}:{操作}:{字段(可选)}
# 示例权限
key-manager:keys:create # 创建密钥
key-manager:keys:read # 查看密钥(不含密钥值)
key-manager:keys:read:value # 查看密钥值(敏感操作)
key-manager:keys:delete # 删除密钥
key-manager:keys:rotate # 轮换密钥
key-manager:keys:grant # 授权他人使用密钥
2.3 角色继承:省事但别滥用
角色继承说白了就是“子角色自动拥有父角色的所有权限”。比如你定义了“密钥管理员”这个父角色,然后“高级密钥管理员”继承它,那高级密钥管理员自然就有了密钥管理员的全部权限。
继承的好处很明显:
- 减少重复配置。你只需定义一次基础权限,然后层层扩展。
- 权限变更时影响范围可控。修改父角色的权限,所有子角色自动生效。
但也别滥用。我见过一个系统,角色继承链条长达7层,最后排查权限问题时,谁也说不清某个权限到底是从哪一层来的。这其实是个反模式。
关于继承,有两条经验规则:
- 继承深度不超过3层。根角色 → 中间角色 → 叶子角色,足够了。
- 避免多继承。就是让一个角色同时继承两个父角色。道理和图模型一样,容易出冲突。如果我不得不做多继承,我会定义一个“优先级规则”——比如A父角色优先级高于B父角色,冲突时以A为准。
2.4 静态职责分离(SSD):防止权限滥用
静态职责分离(SSD)是RBAC里一个非常有用的约束机制。它的核心思想是:某些角色不能同时分配给同一个人。
举个例子,在密钥管理系统里:
- “密钥创建者”可以创建密钥
- “密钥审批者”可以审批密钥
如果一个用户同时拥有这两个角色,他就可以自己创建密钥、自己审批,绕过所有的安全控制。这显然不行。SSD就是用来阻止这种“角色冲突”的。
我在项目中遇到的典型SSD场景:
| 冲突角色对 | 解释 | 为什么不能共存 |
|---|---|---|
| 密钥创建者 ↔ 密钥审批者 | 一个负责创建,一个负责审批 | 防止创建者自己批准自己的密钥请求 |
| 密钥管理员 ↔ 审计员 | 管理员管理密钥,审计员记录日志 | 防止管理员删除自己的操作痕迹 |
| 策略管理者 ↔ 密钥使用者 | 策略管理者制定访问策略,使用者应用策略 | 防止策略管理者为自己开特殊权限 |
SSD的配置方式很简单,就是在角色定义时,指定一个“互斥角色列表”。当给用户分配角色时,系统自动检查这个列表:
# 角色定义示例(伪代码)
role:
name: "密钥创建者"
permissions:
- key-manager:keys:create
ssd_conflicts:
- "密钥审批者"
- "密钥管理员"
role:
name: "密钥审批者"
permissions:
- key-manager:keys:approve
ssd_conflicts:
- "密钥创建者"
- "密钥管理员"
当尝试给用户分配“密钥创建者”时,系统会检查该用户是否已经有“密钥审批者”或“密钥管理员”角色。如果有,分配请求会被拒绝,并返回明确的错误信息。
2.5 本章知识体系总览
下面这张图,把本章四个核心概念的关系串起来了:
从图里你能看到,这四个概念不是孤立的。角色继承会影响SSD的约束传递;权限粒度过细会导致角色层次膨胀。设计时一定要整体考量。
好了,第二章的内容就到这。说白了,权限模型设计就是一场权衡——灵活性和安全性之间的权衡、管理成本和细粒度控制之间的权衡。我给你的建议是:从最简单的三层树形结构开始,用适中的粒度,配上必要的SSD约束。随着业务复杂度提升,再逐步演进,不要一上来就想搞个大而全的模型。