Spring Boot 3 + Vue3 企业级 RBAC 权限框架设计与实战:菜单权限、按钮鉴权与数据范围如何贯通
2026/9/9 20:48:51 网站建设 项目流程

Spring Boot 3 + Vue3 企业级 RBAC 权限框架设计与实战:菜单权限、按钮鉴权与数据范围如何贯通

🌐演示地址:http://ruoyioffice.com | 📦源码1·GitHub:ruoyi-office | 📦源码2·GitCode:ruoyi-office | 📦源码3·Gitee:ruoyi-office | 💬微信:17156169080(备注「RuoYi Office」)

「加个角色表关联菜单」只是 RBAC 的第一公里。企业里真正要命的是:前端按钮藏了,接口还能打;菜单有了,列表却看到全公司工资;Token 过了,租户却串了。本文以 RuoYi Office(Spring Boot 3 + Vue3)为样本,按「功能架构全景」把用户 → 角色 → 菜单/权限 → 数据范围四段链路讲成可落地的实战,而不是概念课。

▲ 分层全景:顶链 User→Role→Menu→DataScope;中层前端交互 / 鉴权引擎 / 数据权限;底层角色菜单用户关联表

引言:企业级 RBAC 要同时挡住三件事

层次要挡住的问题典型技术点
功能权限能不能进菜单、点按钮、调接口菜单permission@PreAuthorizev-access
数据权限点了之后能看哪些行DataScope、Dept 规则、MyBatis 改写
身份与租户你是谁、属于哪个租户世界OAuth2/Token、租户上下文

三者缺一,都会在演示环境「看起来正常」、生产环境「出事」。


一、模型:User – Role – Menu(含按钮)

经典四表(名称以库表为准,业务上认这张关系图即可):

用户 ──< 用户-角色 >── 角色 ──< 角色-菜单 >── 菜单 │ └─ 菜单.type:目录 / 菜单 / 按钮 └─ 菜单.permission:权限标识字符串

要点:

  1. 用户不直接绑菜单——改权限只改角色,避免人走茶凉改不完。
  2. 按钮也是菜单树节点(类型=按钮),权限标识挂在节点上,例如system:user:create
  3. 角色还可挂数据范围(全部 / 本部门 / 本部门及以下 / 自定义部门 / 仅本人)——这是「行级」能力,不是菜单树的一部分。

▲ 角色是权限分配的枢纽:停用角色、调整菜单、设置数据范围,都从这里收敛


二、权限标识:前后端必须是同一字符串

约定俗成:

{模块}:{资源}:{动作} system:user:query system:user:create bpm:task:update

2.1 后端:接口上声明

@PreAuthorize("@ss.hasPermission('system:user:create')")@PostMapping("/create")publicCommonResult<Long>createUser(...){...}

@ss指向安全框架服务,内部会调到权限域的hasAnyPermissions(userId, permissions...)

2.2 权限判定核心逻辑(实战可读版)

// PermissionServiceImpl#hasAnyPermissions(逻辑摘要)List<RoleDO>roles=getEnableUserRoleListByUserIdFromCache(userId);for(Stringpermission:permissions){if(hasAnyPermission(roles,permission))returntrue;}returnroleService.hasAnySuperAdmin(...);// 超管放行

hasAnyPermission采用严格模式

  1. permission反查菜单 ID 列表
  2. 若权限串在菜单里不存在 →直接无权限(防止瞎写标识被默许)
  3. 看这些菜单是否与当前用户角色有交集

缓存加速角色、菜单、菜单-角色关系;空角色缓存会回源 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

实战注意:

  1. 只做前端路由守卫不够——直接调 API 必须拦。
  2. 权限变更后要让缓存失效——改角色菜单后,用户需重新拉取权限或等缓存驱逐,否则「后台改了前台还是旧的」。
  3. 超管与租户管理员要有明确策略,避免所有人用超管账号日常办公。

四、数据范围 DataScope:挡住「行」

功能权限过了,只说明能进「用户列表」接口;还能看到哪些用户,由数据范围决定。

publicenumDataScopeEnum{ALL(1),// 全部DEPT_CUSTOM(2),// 指定部门DEPT_ONLY(3),// 本部门DEPT_AND_CHILD(4),// 本部门及以下SELF(5);// 仅本人}

落地方式(框架层):

  1. 登录用户解析出部门数据权限 DTO(是否全部、部门 ID 集、是否仅本人)
  2. DeptDataPermissionRule等规则在 MyBatis 层拼OR/IN条件
  3. 业务 SQL不必每个手写dept_id = ?,减少遗漏

▲ 角色上配置数据范围:同一「用户查询」权限,经理与职员看到的行集合不同

常见坑:

  • 报表自定义 SQL 绕过规则 → 泄漏
  • 联表别名未登记到规则 → 条件加错表
  • 本该「仅本人」的单据用了「全部」角色联调 → 演示正常、上线事故

五、Vue3 侧:动态路由 + 按钮 + 指令

企业后台通常:

  1. 登录成功拉用户信息与权限码
  2. 按菜单生成侧边栏与动态路由(无权限的路由不注册或进 403)
  3. 页面内按钮用v-access:code或表格操作列auth字段过滤

与 Spring Boot 3 的配合要点:

项目建议
权限码来源只信后端计算,不在前端写死角色名判断
路由 meta可冗余权限码便于调试,仍以接口鉴权为准
多页签权限变更后关闭相关页签并刷新权限
与流程模块流程菜单、办理按钮同样走 permission,不另造「流程管理员口令」

六、实战清单:新增一个「导出」按钮要改哪

以「系统用户导出」为例:

  1. 菜单管理:在用户菜单下新增按钮节点,permission = system:user:export
  2. 角色:给需要的角色勾选该按钮
  3. 后端:导出接口加@PreAuthorize("@ss.hasPermission('system:user:export')")
  4. 前端:导出按钮加v-access:code="['system:user:export']"
  5. 数据范围:导出查询走同一 Mapper,自动吃 DataScope(勿另写无规则 SQL)
  6. 验证:无权限角色 403;有权限但 SELF 范围只能导出自己相关数据

漏掉任何一步,都会出现「能点不能导出」或「不能点却能抓包导出」。


七、和多租户、OAuth2 的边界(实战视角)

  • 租户:多数业务表带tenant_id,权限数据也在租户内;跨租户访问需显式能力(如租户拜访权限),默认拒绝。
  • 认证 vs 鉴权:Token 解决「你是谁」;RBAC 解决「你能做什么」。微服务下常网关认证、服务内鉴权。
  • 缓存:角色菜单变更要设计驱逐;否则「刚授权仍 403 / 刚收回仍能进」。

更完整的三位一体长文可对照仓库内既有权限体系文章;本文聚焦Spring Boot 3 + Vue3 贯通实战与全景分层。


八、端到端体验建议

  1. 演示环境用非超管账号登录,确认侧边栏菜单已裁剪。
  2. 打开角色管理,去掉某按钮权限,刷新后按钮消失,抓包对应接口应 403。
  3. 将角色数据范围改为「仅本人」,列表行数应变少。
  4. 对比超管账号,理解「功能全开 + 数据全开」仅用于运维。

在线演示: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 支持一下!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询