2. 权限模型设计:角色层次、权限粒度、角色继承与静态职责分离

权限模型这东西,说简单也简单,说复杂能让你改半年。我最早做权限系统时,以为弄个角色表、权限表就完事了。结果上线第一天,销售总监和运维总监的权限就打架了——俩人都是“总监”角色,但一个该看的合同数据另一个不该看。嗯,这就是典型的“角色层次没设计好”。

本章咱们就把这四个核心概念掰扯清楚:角色层次、权限粒度、角色继承、静态职责分离。别小看这四点,它们直接决定了你的系统能不能扛住企业级的多变场景。

2.1 角色层次:扁平还是树形?

角色层次解决的是“角色之间的关系怎么组织”。你想想看,公司里有CEO、总监、经理、员工,这些角色天然就有上下级关系。如果只做扁平的角色列表,那你每次分配权限都得给每个角色单独配一遍,累死人。

我做过的教训:有一回,客户要求给所有“部门经理”批量增加一个报表权限。如果是扁平结构,我得遍历所有经理角色,逐个更新。要是用了层次结构,我只需要在高层角色上加一次权限,下层自动继承。两种做法,工作量差了10倍。

常见的角色层次模型有三种:

模型类型 特点 适用场景 我的建议
扁平模型 角色无层级,每个角色独立配置 10个以内角色的小系统 不推荐,扩展性差
树形模型 角色有父子关系,子角色继承父角色的权限 大多数企业级应用 推荐,最常用
图模型 角色允许多继承,关系更灵活 复杂组织架构或跨部门场景 谨慎使用,管理成本高

我个人习惯选用树形模型。为什么?因为图模型虽然灵活,但你很难保证不出现循环继承——A继承B,B又继承A,权限解析时就炸了。树形模型无环,简单可靠。

实践经验:树形层次中,我一般设3-4层就够了。超过4层,角色维护成本会急剧上升,而且权限继承的推理变得困难。你想想,一个权限从顶层角色经过4层传递下来,出问题了你得逐层排查,心累。

2.2 权限粒度:粗还是细?

权限粒度指的是“一条权限控制到什么程度”。是控制到整个模块(比如“密钥管理”),还是控制到具体API(比如“POST /api/keys”),甚至是控制到某个字段(比如“只允许查看密钥的ID,不允许查看密钥值”)?

这里有个经典的权衡:

  • 粗粒度:权限少,管理简单,但控制力弱。比如“密钥管理员”只有一个权限“所有密钥操作”。问题在于:你不能让某个人只负责创建密钥但无权删除。
  • 细粒度:控制力强,但权限数量激增,配置工作量大。比如把每个CRUD操作都拆成独立权限,再加上字段级别的控制。

我的推荐方案是分层混搭:

  1. 服务级(最粗):控制某个角色是否能访问整个密钥服务。
  2. 资源级:控制对密钥、策略、审计日志等不同资源的访问。
  3. 操作级:控制Create、Read、Update、Delete等具体操作。
  4. 字段级(最细):控制某个资源下的敏感字段是否可见。

具体到密钥权限接口,我常用的粒度设计是:

# 权限标识命名规范
# 格式:{服务}:{资源}:{操作}:{字段(可选)}

# 示例权限
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           # 授权他人使用密钥
我曾经踩过的坑:一开始把权限粒度做得太细,每个API端点都配了一个权限,最后光权限列表就有300多个。结果配置角色时,没人记得住哪个权限对应什么功能。后来我改成按“资源+操作”组合,权限数量降到了30个左右,效果反而更好。切记:粒度不是越细越好,够用就行。

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:
    - "密钥创建者"
    - "密钥管理员"

当尝试给用户分配“密钥创建者”时,系统会检查该用户是否已经有“密钥审批者”或“密钥管理员”角色。如果有,分配请求会被拒绝,并返回明确的错误信息。

注意:SSD和角色继承一起用的时候要小心。假设“高级密钥创建者”继承了“密钥创建者”,那它自然也要继承SSD约束。也就是说,“高级密钥创建者”也不能和“密钥审批者”同时分配。这个继承规则一定要在代码里显式处理,不能遗漏。

2.5 本章知识体系总览

下面这张图,把本章四个核心概念的关系串起来了:

权限模型核心概念关系图 权限模型设计 角色层次 权限粒度 角色继承 静态职责分离 属性 树形结构 / 扁平 / 图模型 深度≤4层,避免循环继承 属性 服务级 → 资源级 → 操作级 权限数量控制在30-50个 属性 深度≤3层,避免多继承 子角色自动继承父角色权限 属性 互斥角色对定义 继承关系下SSD透明传递 核心目标:安全、灵活、可维护的权限体系 给架构师的提醒 这四个概念不是独立选择的。例如:角色继承会影响SSD的约束传递; 权限粒度过细会导致角色层次膨胀。设计时需整体权衡。

从图里你能看到,这四个概念不是孤立的。角色继承会影响SSD的约束传递;权限粒度过细会导致角色层次膨胀。设计时一定要整体考量。

好了,第二章的内容就到这。说白了,权限模型设计就是一场权衡——灵活性和安全性之间的权衡、管理成本和细粒度控制之间的权衡。我给你的建议是:从最简单的三层树形结构开始,用适中的粒度,配上必要的SSD约束。随着业务复杂度提升,再逐步演进,不要一上来就想搞个大而全的模型。