4. 基于角色的访问控制(RBAC)

聊到访问控制,RBAC 绝对是个绕不开的话题。说实话,我在企业里做安全架构这些年,RBAC 几乎是我落地最多的模型。为什么?因为它够直观,够灵活。你想想看,一个公司几百上千号人,如果每个人都要单独配权限,那运维同学怕是要疯掉。

RBAC 的核心思想其实很简单:权限不直接给用户,而是给角色,用户通过扮演角色来获得权限。嗯,就这么一句话,但背后的门道可不少。

4.1 RBAC 核心概念

我们先拆开来看三个最基础的概念:角色、权限、会话。

概念 定义 我的一点理解
角色(Role) 一个职责或职务的抽象,比如“财务主管”、“系统管理员” 角色是权限的集合,也是用户和权限之间的桥梁
权限(Permission) 对某个资源执行某种操作的许可,比如“读取订单表”、“删除用户” 权限是最小粒度,通常用“资源+操作”来描述
会话(Session) 用户激活角色集的一次登录过程 用户登录后,系统会创建一个会话,会话里记录了用户当前激活了哪些角色

关键关系:用户 ↔ 角色 ↔ 权限。用户不直接拥有权限,而是通过角色间接获得。这样做的好处是,当人员变动时,你只需要调整用户和角色的关联,而不需要动权限本身。

我记得有一次帮一家电商公司做权限改造,他们原来的系统是直接给每个人配权限的。结果离职交接时,新来的同事总是缺这缺那。后来改成 RBAC,把“运营专员”、“客服主管”这些角色定义好,权限问题一下子就清爽了。

4.2 RBAC 的四个模型层次

RBAC 并不是一个死板的模型,它分了四个层次,从简单到复杂。我个人习惯把这四个层次叫做“RBAC 的进化之路”。

4.2.1 RBAC0 — 基础模型

这是最核心、最基础的部分。它只包含用户、角色、权限、会话这四个要素。说白了,就是“用户-角色-权限”的三元组关系。大多数中小型系统,用 RBAC0 就足够了。

4.2.2 RBAC1 — 角色分级模型

在 RBAC0 的基础上,引入了角色继承。比如“高级工程师”可以继承“初级工程师”的所有权限,然后再加上一些额外的权限。这样做的好处是,你不需要为每个级别都重新定义一遍权限。

避坑指南:我曾经在一个项目中,把角色继承搞成了多层嵌套,结果一个角色继承链长达 7 层。排查权限问题时,根本搞不清某个权限是从哪一层继承来的。我的建议是:继承层级不要超过 3 层,否则维护成本会急剧上升。

4.2.3 RBAC2 — 约束模型

RBAC2 在 RBAC0 的基础上增加了约束条件。常见的约束有:

  • 互斥角色:一个用户不能同时拥有两个互斥的角色。比如“采购员”和“验收员”不能是同一个人,这是典型的职责分离。
  • 基数约束:一个角色最多只能有 N 个用户。比如“CEO”这个角色,只能有一个人。
  • 先决条件角色:要成为“项目经理”,必须先拥有“项目成员”这个角色。

4.2.4 RBAC3 — 统一模型

RBAC3 是 RBAC1 和 RBAC2 的合体,既有角色继承,又有约束条件。这是最完整的 RBAC 模型,也是大型企业系统的首选。

为了让你更直观地理解这四个层次的关系,我画了一张图:

RBAC 模型层次结构 RBAC0 — 基础模型 用户 ↔ 角色 ↔ 权限 + 会话管理 RBAC1 — 角色分级 RBAC0 + 角色继承 RBAC2 — 约束模型 RBAC0 + 互斥/基数/先决条件 RBAC3 — 统一模型 RBAC1 + RBAC2 = 角色继承 + 约束条件 💡 实际项目中,80% 的场景用 RBAC0 就能解决,别一上来就上 RBAC3

4.3 RBAC 在企业系统中的应用

理论说完了,我们聊聊落地。RBAC 在企业系统里到底怎么用?我结合几个真实场景来说。

4.3.1 典型应用场景:ERP 系统

ERP 系统是 RBAC 的经典战场。一个典型的制造企业 ERP,角色可以这样设计:

角色名称 所属部门 核心权限 约束条件
采购员 采购部 创建采购单、查看供应商信息 不能同时担任验收员
验收员 仓储部 验收货物、生成入库单 不能同时担任采购员
财务主管 财务部 审核付款、查看财务报表 基数约束:仅1人
系统管理员 IT部 用户管理、角色管理、审计日志 不能参与业务操作

注意:我曾经见过一个系统,把“系统管理员”和“财务主管”的角色给了同一个人。结果这个人既能改权限,又能审核付款。这等于把保险柜的钥匙和密码给了同一个人。职责分离不是形式,是底线。

4.3.2 会话管理的最佳实践

会话是 RBAC 里容易被忽视的一环。用户登录后,系统会创建一个会话,并激活该用户拥有的角色。这里有几个要点:

  • 最小权限原则:用户登录时,只激活完成当前任务所需的最小角色集。比如一个用户既是“管理员”又是“普通用户”,日常操作时只激活“普通用户”角色,只有在做管理操作时才激活“管理员”角色。
  • 会话超时:长时间不操作,自动销毁会话,防止权限被滥用。
  • 并发会话控制:限制同一个用户不能同时有多个活跃会话,防止权限被共享。

4.3.3 代码示例:RBAC 权限校验

下面是一个简单的权限校验伪代码,展示了 RBAC 的核心逻辑:

// 用户登录,创建会话
Session session = createSession(userId);

// 获取用户拥有的角色列表
List<Role> roles = getRolesByUserId(userId);

// 激活角色(用户可以选择激活哪些角色)
session.activateRoles(roles);

// 权限校验
boolean checkPermission(Session session, String resource, String operation) {
    // 获取会话中已激活的角色
    List<Role> activeRoles = session.getActiveRoles();
    
    for (Role role : activeRoles) {
        // 检查角色是否拥有该权限
        if (role.hasPermission(resource, operation)) {
            return true;
        }
    }
    return false;
}

我的建议:权限校验一定要做在服务端,前端只是展示层面的控制。我见过太多只在前端做权限判断的系统,结果被懂行的用户直接调接口绕过去了。记住,前端控制是面子,后端校验才是里子。

4.3.4 企业落地的常见坑

最后,分享几个我在项目中踩过的坑:

  • 角色爆炸:一开始角色定义得太细,结果出现了几百个角色,比用户还多。我的建议是:角色粒度以“岗位职责”为单位,不要以“单个操作”为单位。
  • 权限冗余:同一个权限被挂在多个角色下,导致修改时漏掉一个。可以用权限矩阵来管理,定期做权限审计。
  • 忽略审计:RBAC 不是配完就完事了。一定要记录谁在什么时候激活了什么角色,做了什么操作。出了事才能追溯。

RBAC 看起来简单,但真正用好它,需要你对业务有深刻的理解。别把它当成一个纯技术问题,它本质上是一个管理问题。技术只是工具,合理的角色设计和权限分配才是核心。