MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第二章:RBAC 权限系统设计

一、什么是 RBAC?

RBAC 全称:

Role-Based Access Control(基于角色的访问控制)

它的思想非常简单:

不给用户直接分配权限,而是先给用户分配角色,再给角色分配权限。

例如:

张三 │ ▼ 管理员 │ ▼ 拥有所有权限

或者:

李四 │ ▼ 普通员工 │ ▼ 查看订单 查看商品 不能删除数据

二、为什么不用直接给用户分配权限?

假设公司有:

  • 1000 名员工
  • 50 种权限

如果直接分配:

张三 ├── 查看用户 ├── 删除用户 ├── 添加商品 ├── 删除商品 ├── 查看订单 ...

1000 人都要单独维护权限。

维护成本非常高。


使用 RBAC:

管理员 ├── 查看用户 ├── 删除用户 ├── 添加商品 ├── 删除商品 运营 ├── 查看商品 ├── 修改商品 客服 ├── 查看订单 ├── 修改订单

用户只需要绑定角色:

张三 ↓ 管理员

如果管理员权限变化:

只修改一次:

管理员角色

所有管理员立即生效。


三、RBAC 的四个核心对象

整个 RBAC 可以抽象成四张核心表:

User(用户) Role(角色) Permission(权限) Menu(菜单,可选)

企业中最常见的是:

User ↓ Role ↓ Permission

四、用户(User)

用户就是登录系统的人。

例如:

idusername
1admin
2tom
3jack

对应 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_idrole_id
11
12
23

表示:

用户1 ↓ 管理员 ↓ 运营

十一、Role 与 Permission(多对多)

同样:

建立:

CREATE TABLE role_permission( role_id BIGINT, permission_id BIGINT );

例如:

role_idpermission_id
11
12
13

十二、最终数据库结构

最终:

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 的核心思想是"用户拥有角色,角色拥有权限",通过角色作为中间层,实现权限的统一管理和灵活扩展。


本章思考题

  1. 为什么 RBAC 不直接把权限分配给用户,而要增加 Role(角色)这一层?
    因为角色是权限的集合,增加角色这一层可以实现权限的统一管理,降低维护成本。
  2. 为什么 User 和 Role、Role 和 Permission 都设计成多对多关系?
    用户可以有多个角色,角色可以有多个权限,因此两者都需要设计成多对多关系。
  3. 为什么多对多关系需要中间表,而不能把多个角色直接存到一个字段中?
    中间表符合数据库范式,支持外键、索引和高效查询,是实现多对多关系的标准方式。
  4. role_namerole_code有什么区别?为什么程序更适合使用role_code
    role_name 用于展示,role_code 用于程序判断,因为 code 稳定,不会因业务名称变化而影响代码。
  5. 如果一个用户同时拥有两个角色,而两个角色都包含同一个权限,最终这个用户应该拥有几次这个权限?为什么?
    多个角色的权限最终会取并集,并自动去重,同一个权限只会生效一次。