一、什么是 RBAC?
RBAC 全称:
Role-Based Access Control(基于角色的访问控制)
它的思想非常简单:
不给用户直接分配权限,而是先给用户分配角色,再给角色分配权限。
例如:
张三
│
▼
管理员
│
▼
拥有所有权限
或者:
李四
│
▼
普通员工
│
▼
查看订单
查看商品
不能删除数据
二、为什么不用直接给用户分配权限?
假设公司有:
- 1000 名员工
- 50 种权限
如果直接分配:
张三
├── 查看用户
├── 删除用户
├── 添加商品
├── 删除商品
├── 查看订单
...
1000 人都要单独维护权限。
维护成本非常高。
使用 RBAC:
管理员
├── 查看用户
├── 删除用户
├── 添加商品
├── 删除商品
运营
├── 查看商品
├── 修改商品
客服
├── 查看订单
├── 修改订单
用户只需要绑定角色:
张三
↓
管理员
如果管理员权限变化:
只修改一次:
管理员角色
所有管理员立即生效。
三、RBAC 的四个核心对象
整个 RBAC 可以抽象成四张核心表:
User(用户)
Role(角色)
Permission(权限)
Menu(菜单,可选)
企业中最常见的是:
User
↓
Role
↓
Permission
四、用户(User)
用户就是登录系统的人。
例如:
| id | username |
|---|---|
| 1 | admin |
| 2 | tom |
| 3 | jack |
对应 SQL:
CREATE TABLE user(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
password VARCHAR(255)
);
这里只保存:
- 登录账号
- 密码
- 手机号
- 邮箱
不要保存权限。
五、角色(Role)
角色代表:
一类人的身份。
例如:
| id | 角色 |
|---|---|
| 1 | 超级管理员 |
| 2 | 管理员 |
| 3 | 运营 |
| 4 | 客服 |
| 5 | 访客 |
SQL:
CREATE TABLE role(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50),
role_code VARCHAR(50)
);
例如:
role_code
ADMIN
USER
OPERATOR
程序一般判断:
role_code
而不是:
role_name
因为:
名称可以修改:
管理员
↓
系统管理员
code:
一般不会变。
六、权限(Permission)
权限:
表示:
系统允许做什么。
例如:
查看用户
新增用户
删除用户
修改用户
查看订单
删除订单
SQL:
CREATE TABLE permission(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
permission_name VARCHAR(100),
permission_code VARCHAR(100)
);
例如:
permission_code
user:list
user:add
user:delete
order:list
order:delete
以后:
NestJS:
Guard:
就是判断:
permission_code
七、为什么需要角色中间层?
很多新人会问:
为什么不能:
用户
↓
权限
原因:
如果:
1000人。
每个人:
50权限。
需要:
50000条关系。
修改:
非常困难。
而:
用户
↓
角色
↓
权限
权限:
只维护:
角色。
维护成本:
极低。
八、表之间关系
现在:
开始画关系。
一个用户:
可以有:
多个角色。
例如:
Tom
↓
管理员
↓
运营
所以:
User:
和:
Role:
是:
多对多
角色:
和:
权限:
也是:
多对多
例如:
管理员:
拥有:
用户管理
商品管理
订单管理
运营:
拥有:
商品管理
订单查看
所以:
Role:
Permission:
也是:
多对多。
九、为什么多对多不能直接存?
例如:
错误设计:
User:
id
username
role
role:
ADMIN,USER
问题:
SQL:
无法:
JOIN。
无法:
建立外键。
无法:
索引。
违反:
第一范式(1NF)。
所以:
需要:
中间表。
十、User 与 Role(多对多)
需要:
user_role:
CREATE TABLE user_role(
user_id BIGINT,
role_id BIGINT
);
例如:
| user_id | role_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
表示:
用户1
↓
管理员
↓
运营
十一、Role 与 Permission(多对多)
同样:
建立:
CREATE TABLE role_permission(
role_id BIGINT,
permission_id BIGINT
);
例如:
| role_id | permission_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
十二、最终数据库结构
最终:
RBAC:
数据库:
User
│
│
│
User_Role
│
│
Role
│
│
Role_Permission
│
│
Permission
或者画得更完整一点:
+---------+ +-------------+ +--------+
| User |<-------> | User_Role |<-------> | Role |
+---------+ +-------------+ +--------+
|
|
v
+------------------+
| Role_Permission |
+------------------+
|
|
v
+--------------+
| Permission |
+--------------+
十三、企业后台权限流程
用户登录:
输入账号密码
↓
查询:
user
↓
查询:
user_role
↓
查询:
role_permission
↓
得到:
permission
↓
生成:
JWT。
以后:
每次请求:
判断:
permission_code
例如:
user:add
有:
允许。
没有:
403。
十四、本章总结
| 表 | 作用 |
|---|---|
| user | 用户 |
| role | 角色 |
| permission | 权限 |
| user_role | 用户角色关系 |
| role_permission | 角色权限关系 |
核心关系:
User
↓
Role
↓
Permission
都是通过中间表建立多对多关系。
🎯 本章核心一句话:
RBAC 的核心思想是"用户拥有角色,角色拥有权限",通过角色作为中间层,实现权限的统一管理和灵活扩展。
本章思考题
- 为什么 RBAC 不直接把权限分配给用户,而要增加 Role(角色)这一层?
因为角色是权限的集合,增加角色这一层可以实现权限的统一管理,降低维护成本。 - 为什么 User 和 Role、Role 和 Permission 都设计成多对多关系?
用户可以有多个角色,角色可以有多个权限,因此两者都需要设计成多对多关系。 - 为什么多对多关系需要中间表,而不能把多个角色直接存到一个字段中?
中间表符合数据库范式,支持外键、索引和高效查询,是实现多对多关系的标准方式。 role_name和role_code有什么区别?为什么程序更适合使用role_code?
role_name 用于展示,role_code 用于程序判断,因为 code 稳定,不会因业务名称变化而影响代码。- 如果一个用户同时拥有两个角色,而两个角色都包含同一个权限,最终这个用户应该拥有几次这个权限?为什么?
多个角色的权限最终会取并集,并自动去重,同一个权限只会生效一次。