4. RBAC1模型:角色分层与权限继承的机制及应用

这一讲,咱们聊聊RBAC1模型。说白了,它就是在RBAC0的基础上加了个“层级”的概念。为什么需要层级?因为现实世界中,角色和角色之间是有高低之分的。

我记得最早接手的一个电商后台系统,权限表那叫一个乱。销售总监和普通销售员,他们的权限列表是各自独立维护的。总监能看销售报表,销售员也能看——但总监还得能修改提成比例,销售员不能。每次调整一个权限,都得去改好几个角色。痛不痛?太痛了。

所以,RBAC1的出现就是为了解决这个痛点。

4.1 什么是角色分层

角色分层,直白点说,就是给角色排个座次。父角色拥有子角色的所有权限,并且还能额外拥有自己独有的权限。

核心定义:

  • 角色之间存在偏序关系(≥)。如果角色A ≥ 角色B,那么A继承B的所有权限。
  • 这种关系具有传递性。A ≥ B, B ≥ C,则A ≥ C。
  • 它一定是反对称的。A ≥ B 且 B ≥ A,则A = B。

你想想看,这不就是公司的组织架构吗?总经理的权限肯定包含部门经理的,部门经理的权限肯定包含小组长的。我们用模型把这个关系固化下来,系统里就不再需要“重复造轮子”了。

4.2 权限继承的机制

权限继承是怎么实现的?这里要区分两种模式,我在项目里都踩过坑。

继承模式 描述 我遇到过的坑
完全继承 子角色拥有父角色的全部权限。通常用于严格的金字塔型组织。 容易让底层角色权限失控,一不小心就给多了。
选择性继承 子角色只能继承父角色指定的权限子集,父角色可以“屏蔽”某个权限不让下放。 灵活性更高,但实现复杂,需要维护继承映射表。

我个人更倾向于选择性继承。原因是完全继承容易导致“权限爆炸”。你给父角色加一个“查看所有工单”的权限,结果连实习生都拥有了这个能力——这太危险了。

4.3 RBAC1与RBAC0的对比

别把这两个模型对立起来。RBAC1是RBAC0的超集。我建议你把它理解为:RBAC0是基础框架,RBAC1加上了角色间的“家谱”。

  • RBAC0:角色是平的,互不相干。你有的权限我可能没有,我有的你也没有。都得单独配。
  • RBAC1:角色是有层级的。你是我爹,你的权限就是我的。我只管管我自己额外的东西就完了。

从数据模型上看,RBAC1比RBAC0多了一张表——角色继承关系表。这张表记录了哪两个角色之间是父子关系。

小提示:我在第一个RBAC系统里就踩了这个坑。直接用层级字段(例如用整数表示级别)去存角色等级,结果发现“级别5”和“级别6”之间没法精确控制哪些权限可以继承。最后还是老老实实加了张关系表,按月归档数据,清晰多了。

4.4 一个真实的例子

来,写一个最简单的模型示例。假设我们有一个公司系统。

# 角色定义
roles = {
    "9b59b6-admin": "管理员",
    "3498db-manager": "经理",
    "2ecc71-editor": "编辑",
    "f39c12-viewer": "查看者"
}

# 角色继承关系(谁是谁的父角色)
role_hierarchy = {
    "manager": ["editor", "viewer"],
    "admin": ["manager"]
}

# 权限分配(每个角色专属的权限)
role_permissions = {
    "admin": ["system.config", "user.delete"],
    "manager": ["report.view", "user.create"],
    "editor": ["content.edit", "content.publish"],
    "viewer": ["content.view"]
}

def get_effective_permissions(role_name):
    """获取一个角色的有效权限(包括继承来的)"""
    effective = set(role_permissions.get(role_name, []))
    
    # 递归查找子角色权限
    def _inherit(role):
        children = role_hierarchy.get(role, [])
        for child in children:
            effective.update(role_permissions.get(child, []))
            _inherit(child)
    
    _inherit(role_name)
    return effective

# 测试一下
print(get_effective_permissions("admin"))
# 输出:{'user.delete', 'report.view', 'system.config', 'content.view', 'content.edit', 'content.publish', 'user.create'}

你会发现,admin角色继承了manager、editor、viewer的所有权限,并且自己还有两个独有权限(system.config、user.delete)。

4.5 设计原则与注意事项

搞RBAC1,有几个原则我建议你记着。

  1. 继承不要超过三层。我见过一个客户,角色层级搞了七八层。最后谁有什么权限谁也搞不清。三层基本就够用了:高管层、业务层、执行层。
  2. 警惕循环继承。A继承B,B继承C,C又继承A——这会导致死循环。我曾经在一次代码评审里就抓到过这样的BUG,还好没上线。
  3. 继承规则要有默认行为。我习惯把所有角色的初始权限都设为“拒绝”,然后通过继承关系慢慢开放。这符合最小权限原则。

避坑指南:我曾经在一个金融系统里,把“查看客户资料”权限放在了某一层角色上,却没有检查下层角色是否也会继承。结果一个客服人员意外看到了所有客户的身份证号。后来,我们在所有敏感权限上都加了一个is_inheritable字段,只有标记为可继承的权限才会被下放。

4.6 知识结构图

下面这张图梳理了RBAC1模型中各个概念的关系和流转。看看就明白了。

RBAC1 角色分层与权限继承示意图 管理员 经理 编辑 查看者 普通用户(操作权限池) 继承规则说明 • 上级拥有下级全部权限 • 同级角色权限不互通 • 支持多级传递继承 高权限角色 低权限角色 操作权限池

4.7 理论落地时的小建议

最后聊点实用的。如果你现在就要开始设计RBAC1方案,我的建议是:

  • 先在纸上画清楚角色的家谱。这一步花不了十分钟,但省了后面无数不必要的争论。
  • 给每个角色设一个“不继承黑名单”。我在某个项目中就给财务总监额外开了一个隐藏权限开关,他可以看到所有部门预算,但这个权限我默认不允许继承给财务经理。
  • 权限变更时,要有审计日志。谁在什么时候修改了哪个角色的继承关系,必须记录。不然出了问题都不知道找谁。