若依框架 RBAC 权限模型与权限校验全解 前言RBAC 权限控制是后台管理系统的核心功能也是 Java 后端面试中项目经历的必问考点。本文基于若依RuoYi框架的源码实现从核心概念、表结构设计、完整校验链路、架构分层、高频疑问等维度系统拆解企业级权限系统的实现原理所有内容均按面试作答标准整理。一、RBAC 核心概念1. 什么是 RBACRBAC 全称Role-Based Access Control基于角色的权限控制核心思想是不直接给用户赋权限而是给角色赋权限再将用户分配给角色通过角色作为中间层实现用户与权限的解耦。2. 为什么要设计角色这一层核心解决权限复用和管理效率问题如果 100 个用户拥有相同权限无需给 100 个用户分别赋权只需给一个角色赋权所有用户继承角色权限即可修改权限时只需修改角色无需批量修改所有用户用户离职 / 入职时只需修改用户 - 角色关联无需改动权限配置二、若依 RBAC 五张表设计采用「3 张主表 2 张中间表」的经典设计解决多对多关系表格表名类型作用sys_user主表存储所有用户信息sys_role主表存储所有角色超级管理员、普通用户、访客等sys_menu主表存储所有菜单和权限通过 type 字段区分type0目录type1菜单type2按钮权限sys_user_role中间表存储用户 - 角色的多对多关联关系sys_role_menu中间表存储角色 - 权限的多对多关联关系核心关系用户 ↔ 角色多对多一个用户可拥有多个角色一个角色可分配给多个用户角色 ↔ 权限多对多一个角色可拥有多个权限一个权限可分配给多个角色三、核心概念澄清1. JWT 全称与作用JWT 全称JSON Web Token翻译为「JSON 格式的 Web 身份令牌」是行业标准的身份凭证格式通过签名机制保证数据防篡改用于前后端跨域、分布式场景下的身份传递。若依采用「JWT 外壳 Redis 存储」的混合模式JWT 只存轻量的 UUID 标识和用户名核心用户信息和权限全存在 Redis 中。2. SecurityContextHolder 的生命周期与作用底层实现基于ThreadLocal实现线程级别的临时存储作用当前请求处理期间全局可获取当前登录用户信息非常重要的生命周期仅当前请求有效请求结束立即清空Tomcat 每个请求分配独立线程请求结束线程回收ThreadLocal 数据自动清空下一个请求是新线程ThreadLocal 为空必须重新解析 JWT、重新存入核心误区不是存进去就一劳永逸了每个请求都要重新解析 JWT、重新校验、重新存入四、权限校验完整全链路从点击按钮到接口放行第 1 步前端请求携带 Token登录成功后前端将完整 JWT Token 存入localStorage每次请求自动在请求头携带 Token格式固定Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...第 2 步JWT 过滤器解析身份每个请求都会执行请求进入后端先经过JwtAuthenticationTokenFilter过滤器固定执行 4 步校验 JWT 签名合法性判断是否过期、是否被篡改解析 JWT 载荷取出 UUID 登录标识拿着 UUID 去 Redis 查询login_tokens: UUID取出完整的LoginUser对象包含用户所有权限集合将LoginUser存入SecurityContextHolder当前请求处理期间全局可获取第 3 步AOP 切面拦截执行权限校验请求到达 Controller 方法前Spring AOP 切面拦截方法上的权限注解javaPreAuthorize(ss.hasPermi(system:user:list))ss是 Spring Bean 名称对应PermissionService权限校验服务类自动调用hasPermi方法将注解中的权限标识作为参数传入第 4 步最终权限比对PermissionService.hasPermi()方法核心逻辑javapublic boolean hasPermi(String permission) { // 1. 从SecurityContextHolder取出当前登录用户 LoginUser loginUser SecurityUtils.getLoginUser(); // 2. 取出用户拥有的所有权限标识集合 SetString permissions loginUser.getPermissions(); // 3. 字符串精确匹配用户权限集合是否包含接口要求的权限 return permissions.contains(permission); }匹配成功放行执行接口方法匹配失败直接返回 403 权限不足方法不会执行关键设计前后端双重校验前端根据权限自动隐藏无权限的按钮提升用户体验后端接口层做最终权限校验防止绕过前端直接调用接口这是真正的安全防线五、若依分层架构设计若依采用标准的企业级分层架构每层职责单一高内聚低耦合表格层级目录职责控制层ruoyi-admin/web/controller接收请求、返回结果不写业务逻辑按业务模块细分system系统管理、common通用接口等业务层service处理核心业务逻辑不直接操作数据库数据层mapper只写 SQL负责数据库读写操作框架层ruoyi-framework封装通用框架能力Security 配置、JWT 过滤器、异步任务、权限服务公共层ruoyi-common存放所有模块通用的工具类、常量、异常、统一响应封装分层的核心优势解耦每层职责单一修改数据库不用改业务修改业务不用改接口复用业务逻辑可被多个 Controller 复用工具类所有模块通用易维护出问题快速定位到对应层级便于排查和迭代六、高频面试题 标准答案Q1什么是 RBAC为什么要基于角色做权限控制答RBAC 是基于角色的访问控制核心思想是通过角色作为中间层将用户和权限解耦。 不直接给用户赋权而是给角色赋权再分配用户主要是为了权限复用和提升管理效率批量用户的权限变更只需修改角色即可不用逐个用户操作。Q2若依实现 RBAC 用了哪几张表关系是什么答用了 5 张表3 张主表 sys_user、sys_role、sys_menu2 张中间表 sys_user_role、sys_role_menu。 用户和角色是多对多关系角色和权限是多对多关系通过中间表存储关联。Q3JWT 是什么若依的 Token 模式有什么优势答JWT 全称 JSON Web Token是标准的身份令牌格式通过签名防篡改。 若依采用 JWTRedis 混合模式JWT 只存轻量标识核心信息存 Redis既保留了 JWT 防篡改的安全性又能实现主动踢人、权限即时生效、自动续期等灵活能力。Q4SecurityContextHolder 是做什么的每个请求都要重新存吗答SecurityContextHolder 基于 ThreadLocal 实现是当前请求期间临时存储用户信息的容器。 每个请求都要重新解析 JWT 重新存入因为它是线程级别的请求结束线程回收数据就清空了下一个请求是新线程必须重新校验身份。Q5PreAuthorize 注解的作用是什么ss 是什么答PreAuthorize是 Spring Security 提供的权限注解基于 AOP 切面在方法执行前做权限校验。ss是 Spring Bean 的名称对应PermissionService权限校验服务类hasPermi方法会比对当前用户是否拥有指定权限。Q6为什么前端隐藏了按钮后端还要做权限校验答前端隐藏按钮只是体验层的优化无法保证安全攻击者可以绕过前端直接调用接口。后端接口层的权限校验才是真正的安全防线无论前端怎么操作后端都会做最终校验保证权限安全。七、总结若依的 RBAC 权限系统是企业级后台权限设计的经典实现通过角色解耦用户和权限采用 JWTRedis 混合模式存储登录态基于 AOP 切面做接口级别的权限校验配合标准的分层架构兼顾了安全性、灵活性和可维护性。理解这套设计不仅能应对面试中项目经历的提问也能作为自己开发后台系统的参考方案。