五张表按user、role、permission、user_role、role_permission拆分最稳妥;user表只存身份信息,role表存元数据,permission用层级路径设计,关联表须建联合唯一索引。

RBAC五张表怎么建才不翻车
直接说结论:五张表不是必须的,但按 user、role、permission、user_role、role_permission 拆开最稳妥,能应对绝大多数权限变更和审计需求。
常见错误是把角色和权限硬编码进 user 表(比如加个 role_type 字段),或者用 JSON 字段存权限列表——查不了、索引不了、改起来像拆炸弹。
-
user表只存用户身份信息,不存任何角色或权限字段 -
role表只存角色元数据(name、code、description),别加状态字段除非真需要“禁用角色”逻辑 -
permission表推荐用层级路径式设计,比如system:user:read、order:pay:submit,别用中文或长描述作主键 - 两个关联表必须设联合唯一索引:
user_role(user_id, role_id)和role_permission(role_id, permission_id),否则重复授权会静默失败
Spring Security里怎么把数据库查出来的权限喂给框架
关键不是“怎么查”,而是“查完怎么包装成 GrantedAuthority”。Spring Security 不认角色名或权限码字符串,只认实现了这个接口的对象。
最容易踩的坑是:查出 ["ADMIN", "EDITOR"] 就直接 new SimpleGrantedAuthority("ADMIN") ——这只能匹配 @PreAuthorize("hasRole('ADMIN')"),但没法支持细粒度的 hasAuthority('system:user:delete')。
立即学习“Java免费学习笔记(深入)”;
- 从数据库查出用户所有
permission记录后,统一转成SimpleGrantedAuthority实例,不要混用ROLE_前缀(除非你明确要用hasRole()) - 如果同时要支持角色和权限两种校验,就都用
hasAuthority(),把角色也当成一种权限(如"ROLE_ADMIN"),避免逻辑分裂 - 别在
UserDetails实现类里每次调用都查库——务必缓存,或用 Spring Cache 注解,否则一个页面加载触发 5 次权限查询很常见
MyBatis 查询权限时为什么总漏数据或 N+1
典型症状:用户有 3 个角色,每个角色有 4 条权限,结果只查出 2 条;或者页面打开慢,日志里刷出一串 SELECT * FROM permission WHERE role_id = ?。
根本原因是没处理好关联关系映射。MyBatis 默认不会自动拼装多对多结果,靠 resultMap 手动收口时极易出错。
- 别用
<collection></collection>嵌套查询(即 select 属性指向另一个 mapper 方法),这是 N+1 温床;改用<collection></collection>的select+column映射,或更干脆——用单条 JOIN SQL 查全量 - JPA 用户注意:
@ManyToMany默认懒加载,Controller 层直接返回含权限的 User DTO 会抛LazyInitializationException;要么开spring.jpa.open-in-view=true(不推荐),要么用@EntityGraph显式抓取 - JOIN 查询时,如果用户有多个角色且角色有重叠权限,
permission行会重复——用resultMap的id字段去重,或 Java 层用Set收集
权限变更后前端按钮还是灰的?排查链路在哪断了
这不是前端问题,90% 是后端没把新权限同步到当前会话上下文。JWT 场景尤其明显:权限改了,token 没过期,旧 token 里的权限字段就永远不变。
真实情况是,权限判断发生在拦截器或 AOP 切面里,而它读的是内存中的 Authentication 对象——这个对象通常只在登录时初始化一次。
- 如果是 session 登录,改权限后调用
SecurityContextHolder.getContext().setAuthentication(...)刷新当前会话(需重新查库构造) - 如果是 JWT,别往 token payload 里塞权限列表;改为每次请求校验时实时查库,或引入 Redis 缓存“用户权限版本号”,token 中带 version,查库前先比对
- 前端发请求前不校验按钮状态,而是靠后端接口返回 403——这才是可靠方式;前端“记忆”的权限状态只是体验优化,不是权威来源
权限系统最麻烦的从来不是建表或写注解,而是让“权限变更”这件事真正穿透整个请求生命周期。缓存、token、会话、前端状态,任何一环没对齐,就会出现“明明改了权限,就是不生效”的情况。










