什么是 RBAC?用户-角色-权限的表结构怎么设计?
- 标签:Spring Security、认证授权、后端
🏛 业务架构师
RBAC(Role-Based Access Control,基于角色的访问控制):用户 → 角色 → 权限 的间接授权模型——权限挂在角色上,用户通过角色获得权限。价值:授权管理从"每用户配每权限"(M×N 爆炸)变成"角色"这一中间层批量管理——入职给角色、转岗换角色、离职删关联,权限治理有了组织化的抓手。
经典表结构(五表模型):
sql
-- 用户表
user(id, username, password_hash, status, ...)
-- 角色表
role(id, role_code, role_name, ...) -- 如 ADMIN/OPERATOR
-- 权限表(菜单+按钮/API 两类)
permission(id, perm_code, perm_name, resource, action)
-- 用户-角色关联(多对多)
user_role(user_id, role_id)
-- 角色-权限关联(多对多)
role_permission(role_id, permission_id)设计要点(踩坑经验):
- 多租户:企业 SaaS 必须给五表都加
tenant_id,且角色体系按租户隔离(每租户自定义角色)或"平台预置+租户扩展"分层; - 权限粒度三层:菜单/页面(前端显隐)、API/操作(perm_code 对应 Spring Security 的 authority,如
order:delete)、数据行级(区域/部门过滤——RBAC 管不了数据权限,要叠加数据规则表或部门树 scope 字段); - 角色爆炸防治:控制角色数量(超 30 个说明粒度失控);需要"临时组合"时用"角色+用户直接授权"混合(RBAC1 的继承慎用,复杂度不可控);
- 审计字段:谁授的权、何时授的、何时过期——等保合规必备。
与 Spring Security 对接:登录时把用户的所有 permission perm_code 聚合为 authorities 装进 Authentication,@PreAuthorize("hasAuthority('order:delete')") 直接生效——表结构设计时 perm_code 命名规范(资源:动作)就是未来的注解文案。
🏗 系统架构师
RBAC(Role-Based Access Control)= 用户 → 角色 → 权限的间接授权模型:权限挂角色、用户挂角色——间接层带来管理复杂度从 M×N 降为 M+N(千人系统直接管"人×权限"是不可能的)。
标准五表设计(生产版含实体表):
sql
-- 用户表
user(id, username, password_hash, status, ...)
-- 角色表
role(id, code, name, data_scope) -- data_scope: 数据权限范围标记
-- 权限表(两级:菜单/API 归一建模)
permission(id, code, name, type, -- MENU / BUTTON / API
parent_id, path, sort)
-- 用户-角色
user_role(user_id, role_id) -- UQ(user_id, role_id)
-- 角色-权限
role_permission(role_id, permission_id)
-- 数据级权限(进阶):规则挂在角色上
-- role_data_rule(role_id, table_name, rule_expr)设计要点(架构师经验):
- 权限点建模统一:菜单、按钮、API 端点都进 permission(type 区分)——前后端同一套权限码(
order:export),前端控显隐、后端控执行,双重校验(前端控显只是体验,后端才是防线); - 角色是稳定职责的抽象:按岗位/职责定义(运营专员、财务审核),拒绝"一人一角色"退化(角色爆炸 = RBAC 失效信号);临时授权走"角色 + 有效期"扩展列;
- 用户多角色权限并集,冲突时显式 deny 优先或按最严格策略(团队要统一约定);
- 数据权限分离:功能权限(能不能调)与数据权限(能看哪些行:本人/本部门/全部)是两个维度——
data_scope字段或独立规则表,SQL 层注入过滤条件(MyBatis 拦截器/SpEL),不要在业务代码里散落 if; - 规模化演进:RBAC → 加属性(ABAC:部门、密级、区域动态判定)→ 策略引擎外置(权限即配置)。
缓存与一致性:权限集缓存(Redis + 用户级版本号),改权限广播失效——权限变更的生效延迟要明确 SLA(踢人场景见 JWT 注销专题)。
💻 全栈开发专家
RBAC(Role-Based Access Control,基于角色的访问控制):用户 → 角色 → 权限 三级映射——权限挂在角色上,用户通过角色获得权限。价值:授权管理从「每人每资源」变成「角色定义一次、成员批量管」。
标准表结构(五表模型,我的生产版):
sql
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY,
username VARCHAR(64) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL, -- BCrypt
enabled TINYINT DEFAULT 1
);
-- 角色表(权限的聚合单位)
CREATE TABLE sys_role (
id BIGINT PRIMARY KEY,
role_code VARCHAR(64) NOT NULL UNIQUE, -- ADMIN / ORDER_MGR,代码里用 code
role_name VARCHAR(64)
);
-- 权限表(原子操作点)
CREATE TABLE sys_permission (
id BIGINT PRIMARY KEY,
perm_code VARCHAR(128) NOT NULL UNIQUE, -- order:read / order:refund
resource VARCHAR(64), method VARCHAR(16) -- 可选:绑定菜单/按钮/接口
);
CREATE TABLE sys_user_role ( -- 用户-角色 N:N
user_id BIGINT, role_id BIGINT,
PRIMARY KEY(user_id, role_id)
);
CREATE TABLE sys_role_permission ( -- 角色-权限 N:N
role_id BIGINT, perm_id BIGINT,
PRIMARY KEY(role_id, perm_id)
);设计要点(实战):
- code 参与鉴权,name 给人看——权限判断
hasAuthority("order:refund"),改名不影响代码; - 权限粒度到操作点(资源:动作),不到 URL(URL 与权限解耦,前端菜单和后端接口共用一套);
- 用户角色变更 → 踢缓存重登录(JWT 场景配 token_version);
- 扩展位:角色加
data_scope字段(本部门/本部门及以下/全部)做数据权限;多租户加 tenant_id 全表贯穿; - 别过度设计:小系统角色直接嵌权限(三表)就够,五表是权限点会持续膨胀时才需要。
加载到 Spring Security:UserDetails.authorities = permissions(角色聚合后去重的权限集)。