3. RBAC模型详解:基于角色的访问控制

RBAC,全称是 Role-Based Access Control。说白了,就是「用户不直接拥有权限,而是通过角色来获得权限」。这个思想在业界已经非常成熟了,我最早接触它是在做企业级 ERP 系统的时候。当时客户有上千个员工,如果每个人单独配权限,那简直是噩梦。RBAC 的出现,算是把权限管理从「手工作坊」拉到了「工业化生产」。

你想想看,一个公司里,职位是相对稳定的。销售经理、财务专员、运维工程师……这些角色不会天天变。但具体到每个人,入职、离职、转岗却很频繁。RBAC 的核心就是:把权限赋予角色,再把角色赋予用户。这样一来,人员变动时,我只需要调整他的角色,不用去改那一堆细碎的权限点。

核心公式:用户 → 角色 → 权限

用户与角色是多对多关系,角色与权限也是多对多关系。中间这一层「角色」,就是整个模型的灵魂。

3.1 RBAC0:最核心的基础模型

RBAC0 是所有 RBAC 变体的地基。它定义了三个基本要素:用户(User)、角色(Role)、权限(Permission)。以及它们之间的关联关系。

我在项目中见过不少团队,一上来就想搞复杂的角色继承,结果连 RBAC0 都没跑通。我的建议是:先把 RBAC0 做扎实,再考虑扩展。RBAC0 的核心约束只有一条:一个用户可以拥有多个角色,一个角色可以赋予多个用户;一个角色可以拥有多个权限,一个权限也可以被多个角色拥有。

来看一个最简单的数据表设计思路:

-- 用户表
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

-- 角色表
CREATE TABLE roles (
    id INT PRIMARY KEY,
    role_name VARCHAR(50) NOT NULL
);

-- 权限表
CREATE TABLE permissions (
    id INT PRIMARY KEY,
    perm_code VARCHAR(100) NOT NULL,
    perm_desc VARCHAR(200)
);

-- 用户-角色关联表
CREATE TABLE user_roles (
    user_id INT,
    role_id INT,
    PRIMARY KEY (user_id, role_id)
);

-- 角色-权限关联表
CREATE TABLE role_permissions (
    role_id INT,
    perm_id INT,
    PRIMARY KEY (role_id, perm_id)
);

这个结构看起来简单,但非常实用。我曾经帮一个创业公司重构权限模块,他们之前把权限直接挂在用户字段里,用逗号分隔。后来用户量到了 5000,查询性能直接崩了。改成 RBAC0 之后,不仅查询快了,权限的审计也清晰多了。

小技巧:权限编码(perm_code)建议用「模块:操作:资源」的格式,比如 order:create:all 或 report:view:self。这样在代码里做权限判断时,字符串匹配非常直观。

3.2 RBAC1:角色继承,让层级更自然

RBAC1 在 RBAC0 的基础上,引入了角色继承的概念。什么意思呢?就是角色之间可以有上下级关系。比如「高级工程师」继承「工程师」的所有权限,然后再加上一些额外的权限。

为什么会需要这个?我举个例子。在一个研发团队里,有「开发工程师」和「技术经理」两个角色。技术经理除了拥有开发工程师的所有权限(比如查看代码、提交代码),还应该有「审批合并请求」和「查看项目报表」的权限。如果没有继承,我就得把开发工程师的权限再给技术经理配一遍。这显然很蠢。

角色继承分为两种:

  • 多继承:一个角色可以继承多个父角色。比如「项目经理」同时继承「开发工程师」和「测试工程师」的权限。
  • 单继承:一个角色只能继承一个父角色,形成树状结构。比如「总监」→「经理」→「主管」→「员工」。

我个人更推荐单继承,除非业务有非常强的多继承需求。因为多继承容易引发「菱形继承」问题——两个父角色有相同的权限,子角色到底该用谁的?虽然技术上可以解决(比如取并集),但逻辑上容易把人绕晕。

避坑指南:我曾经在一个项目中允许了 5 层以上的角色继承。结果权限排查时,一个用户到底有哪些权限,要递归查 5 层角色树。性能开销大不说,出问题时根本说不清。后来我强制限制继承深度不超过 3 层。记住:继承不是越深越好。

3.3 RBAC2:约束模型,给权限上「紧箍咒」

RBAC2 在 RBAC0 的基础上,增加了各种约束条件。说白了,就是防止权限滥用。常见的约束有四种:

约束类型 说明 实际例子
互斥角色 一个用户不能同时拥有两个互斥的角色 「采购员」和「验收员」不能是同一个人,防止舞弊
基数约束 一个角色最多能分配给多少个用户 「CEO」角色只能分配给 1 个用户
先决条件角色 用户必须先拥有角色 A,才能拥有角色 B 必须先有「初级工程师」,才能申请「高级工程师」
会话约束 用户在一次会话中只能激活部分角色 一个人同时是「管理员」和「普通用户」,登录时只能选一个角色激活

嗯,这里要注意。互斥角色是最容易出问题的。我在做金融系统时,监管要求「交易录入」和「交易审核」必须由不同的人操作。如果系统没有互斥约束,开发人员可能会忘记在代码里做校验,导致合规风险。所以,互斥约束最好在权限框架层面就强制实现,而不是靠业务代码去保证。

实现思路:在分配角色时,检查当前用户是否已经拥有与目标角色互斥的角色。如果有,直接拒绝分配。这个逻辑可以封装在权限服务的核心方法里,所有调用方都走同一个入口。

3.4 RBAC3:统一模型,集大成者

RBAC3 就是把 RBAC0、RBAC1、RBAC2 全部整合在一起。它既有角色继承,又有各种约束。说白了,RBAC3 就是生产环境里最常用的完整模型。

你可能会问:那为什么不直接上 RBAC3?我的经验是:看业务复杂度。如果只是一个内部管理系统,几十个用户,RBAC0 完全够用。如果是像电商平台、金融系统这种,用户量大、角色层级多、合规要求高,那 RBAC3 才是正确的选择。

下面这张图展示了 RBAC3 的整体结构:

RBAC3 统一模型结构图 用户 (Users) 角色 (Roles) 权限 (Permissions) 角色继承 约束条件 约束类型 • 互斥角色 • 基数约束 • 先决条件角色 继承方式 • 单继承(树状) • 多继承(DAG) • 深度限制 ≤ 3 层 RBAC3 = RBAC0(基础)+ RBAC1(继承)+ RBAC2(约束)

从图上可以看得很清楚:用户通过「用户-角色分配」获得角色,角色通过「角色-权限分配」获得权限。同时,角色之间可以继承(RBAC1),整个分配过程受到各种约束的限制(RBAC2)。这就是 RBAC3 的全貌。

落地建议:不要试图一次性实现 RBAC3 的所有特性。我通常的做法是:先上线 RBAC0,跑通核心流程。然后根据业务反馈,逐步加入角色继承和约束。这样风险最小,也最容易让团队接受。

3.5 模型选型对照表

最后,我整理了一个选型对照表,方便你在实际项目中做决策:

模型 核心能力 适用场景 复杂度
RBAC0 用户-角色-权限三层映射 小型系统、内部工具、用户量 < 1000 低
RBAC1 角色继承、权限复用 组织层级清晰的企业系统 中
RBAC2 互斥、基数、先决条件约束 金融、医疗等强合规行业 中高
RBAC3 继承 + 约束 全支持 大型复杂业务系统 高

嗯,总结一下。RBAC 的核心思想就是「解耦」——把用户和权限解耦,中间加一层角色。RBAC0 是地基,RBAC1 和 RBAC2 是扩展,RBAC3 是完整形态。你在实际项目中,从 RBAC0 起步,按需演进,这才是最务实的做法。