
Spring Boot 3 Vue3 企业级 RBAC 权限框架设计与实战菜单权限、按钮鉴权与数据范围如何贯通演示地址http://ruoyioffice.com | 源码1·GitHubruoyi-office | 源码2·GitCoderuoyi-office | 源码3·Giteeruoyi-office | 微信17156169080备注「RuoYi Office」「加个角色表关联菜单」只是 RBAC 的第一公里。企业里真正要命的是前端按钮藏了接口还能打菜单有了列表却看到全公司工资Token 过了租户却串了。本文以 RuoYi OfficeSpring Boot 3 Vue3为样本按「功能架构全景」把用户 → 角色 → 菜单/权限 → 数据范围四段链路讲成可落地的实战而不是概念课。▲ 分层全景顶链 User→Role→Menu→DataScope中层前端交互 / 鉴权引擎 / 数据权限底层角色菜单用户关联表引言企业级 RBAC 要同时挡住三件事层次要挡住的问题典型技术点功能权限能不能进菜单、点按钮、调接口菜单permission、PreAuthorize、v-access数据权限点了之后能看哪些行DataScope、Dept 规则、MyBatis 改写身份与租户你是谁、属于哪个租户世界OAuth2/Token、租户上下文三者缺一都会在演示环境「看起来正常」、生产环境「出事」。一、模型User – Role – Menu含按钮经典四表名称以库表为准业务上认这张关系图即可用户 ── 用户-角色 ── 角色 ── 角色-菜单 ── 菜单 │ └─ 菜单.type目录 / 菜单 / 按钮 └─ 菜单.permission权限标识字符串要点用户不直接绑菜单——改权限只改角色避免人走茶凉改不完。按钮也是菜单树节点类型按钮权限标识挂在节点上例如system:user:create。角色还可挂数据范围全部 / 本部门 / 本部门及以下 / 自定义部门 / 仅本人——这是「行级」能力不是菜单树的一部分。▲ 角色是权限分配的枢纽停用角色、调整菜单、设置数据范围都从这里收敛二、权限标识前后端必须是同一字符串约定俗成{模块}:{资源}:{动作} system:user:query system:user:create bpm:task:update2.1 后端接口上声明PreAuthorize(ss.hasPermission(system:user:create))PostMapping(/create)publicCommonResultLongcreateUser(...){...}ss指向安全框架服务内部会调到权限域的hasAnyPermissions(userId, permissions...)。2.2 权限判定核心逻辑实战可读版// PermissionServiceImpl#hasAnyPermissions逻辑摘要ListRoleDOrolesgetEnableUserRoleListByUserIdFromCache(userId);for(Stringpermission:permissions){if(hasAnyPermission(roles,permission))returntrue;}returnroleService.hasAnySuperAdmin(...);// 超管放行hasAnyPermission采用严格模式用permission反查菜单 ID 列表若权限串在菜单里不存在 →直接无权限防止瞎写标识被默许看这些菜单是否与当前用户角色有交集缓存加速角色、菜单、菜单-角色关系空角色缓存会回源 DB避免错误租户上下文把「空集」污染 Redis 后长期无权限。2.3 前端按钮同源Button v-access:code[system:user:create]新增/Button或const{hasAccessByCodes}useAccess();hasAccessByCodes([bpm:task:update]);登录后权限码集合来自后端随用户角色菜单计算。前端隐藏只是体验后端注解才是安全边界。两端字符串不一致是权限事故的头号来源。▲ 给角色勾选菜单树含按钮时实际在维护「角色 ↔ 权限标识」集合三、请求链路从 Token 到PreAuthorize浏览器携带 Token → 网关/过滤器解析登录用户 → Controller 方法 PreAuthorize → SecurityFrameworkService.hasAnyPermissions → PermissionApi / PermissionService角色∩菜单 → 通过则进业务否则 403实战注意只做前端路由守卫不够——直接调 API 必须拦。权限变更后要让缓存失效——改角色菜单后用户需重新拉取权限或等缓存驱逐否则「后台改了前台还是旧的」。超管与租户管理员要有明确策略避免所有人用超管账号日常办公。四、数据范围 DataScope挡住「行」功能权限过了只说明能进「用户列表」接口还能看到哪些用户由数据范围决定。publicenumDataScopeEnum{ALL(1),// 全部DEPT_CUSTOM(2),// 指定部门DEPT_ONLY(3),// 本部门DEPT_AND_CHILD(4),// 本部门及以下SELF(5);// 仅本人}落地方式框架层登录用户解析出部门数据权限 DTO是否全部、部门 ID 集、是否仅本人DeptDataPermissionRule等规则在 MyBatis 层拼OR/IN条件业务 SQL不必每个手写dept_id ?减少遗漏▲ 角色上配置数据范围同一「用户查询」权限经理与职员看到的行集合不同常见坑报表自定义 SQL 绕过规则 → 泄漏联表别名未登记到规则 → 条件加错表本该「仅本人」的单据用了「全部」角色联调 → 演示正常、上线事故五、Vue3 侧动态路由 按钮 指令企业后台通常登录成功拉用户信息与权限码按菜单生成侧边栏与动态路由无权限的路由不注册或进 403页面内按钮用v-access:code或表格操作列auth字段过滤与 Spring Boot 3 的配合要点项目建议权限码来源只信后端计算不在前端写死角色名判断路由 meta可冗余权限码便于调试仍以接口鉴权为准多页签权限变更后关闭相关页签并刷新权限与流程模块流程菜单、办理按钮同样走 permission不另造「流程管理员口令」六、实战清单新增一个「导出」按钮要改哪以「系统用户导出」为例菜单管理在用户菜单下新增按钮节点permission system:user:export角色给需要的角色勾选该按钮后端导出接口加PreAuthorize(ss.hasPermission(system:user:export))前端导出按钮加v-access:code[system:user:export]数据范围导出查询走同一 Mapper自动吃 DataScope勿另写无规则 SQL验证无权限角色 403有权限但 SELF 范围只能导出自己相关数据漏掉任何一步都会出现「能点不能导出」或「不能点却能抓包导出」。七、和多租户、OAuth2 的边界实战视角租户多数业务表带tenant_id权限数据也在租户内跨租户访问需显式能力如租户拜访权限默认拒绝。认证 vs 鉴权Token 解决「你是谁」RBAC 解决「你能做什么」。微服务下常网关认证、服务内鉴权。缓存角色菜单变更要设计驱逐否则「刚授权仍 403 / 刚收回仍能进」。更完整的三位一体长文可对照仓库内既有权限体系文章本文聚焦Spring Boot 3 Vue3 贯通实战与全景分层。八、端到端体验建议演示环境用非超管账号登录确认侧边栏菜单已裁剪。打开角色管理去掉某按钮权限刷新后按钮消失抓包对应接口应 403。将角色数据范围改为「仅本人」列表行数应变少。对比超管账号理解「功能全开 数据全开」仅用于运维。在线演示http://ruoyioffice.com源码仓库GitHub | GitCode | Gitee常见问题FAQ为什么权限标识在菜单不存在就判无权限严格模式避免开发者随意写PreAuthorize(xxx)却从未录入菜单导致「以为有校验其实永远 false / 或被错误放行」。标识必须先进菜单树。前端用角色 code 判断可以吗短期方便长期难维护角色合并、重命名。优先权限码角色码仅用于少数「整角」场景。数据权限能否只用 MyBatis 插件、不要角色配置插件是执行器范围数据仍来自角色/用户配置。没有配置源插件不知道该滤哪些部门。和字段权限、流程节点权限是什么关系RBAC 管「系统功能与行级数据」流程里字段可写/只读、节点按钮开关是 BPM 上下文能力二者互补不要混成一个开关。结语Spring Boot 3 Vue3 做企业 RBAC成败不在「有没有角色表」而在权限标识前后端同源、接口强制鉴权、数据范围在 ORM 层自动生效、缓存与租户不串味。RuoYi Office 把这套管线做成可运行的默认能力——你加业务模块时按「菜单按钮 → 注解 → v-access → DataScope」清单走比从零发明一套权限中心可靠得多。你们现在卡在「按钮权限」还是「数据范围」有没有出现过前端藏了接口没拦欢迎评论区交流。想要体验 RuoYi Office 的强大功能在线演示http://ruoyioffice.com/web/账号 admin / admin123源码仓库GitHub | GitCode | Gitee技术咨询添加微信17156169080备注「RuoYi Office」⭐如果觉得不错请给个 Star 支持一下