基于 Spring Boot 权限管理 RBAC 模型

一、 核心架构:RBAC 三巨头

本系统采用经典的 RBAC 模型,其核心思想是:用户不直接关联权限,而是通过"角色"作为中间桥梁。

1. 实体关系图 (ER Diagram)

整个权限体系由 三张实体表 和 两张关联表 支撑:

  1. 用户关联角色 关联
  2. 角色分配菜单 关联
    system_user
    bigint
    id
    我是谁
    string
    username
    USER_ROLE
    system_role
    bigint
    id
    我是什么身份
    string
    code
    如: admin, hr
    ROLE_MENU
    system_menu
    bigint
    id
    我能干什么
    string
    permission
    如: system:user:add
    string
    component
    Vue组件路径

2. 表结构解析

  • system_user (用户表):代表"自然人"。只负责登录,不直接记录权限。
  • system_role (角色表):代表"身份/职位"(如:超级管理员、HR、财务)。它是连接用户和资源的纽带。
  • system_menu (菜单/权限表):代表"资源"。它不仅包含左侧可见的菜单,还包含页面内不可见的按钮(API 权限)。

二、 核心资产:深入理解 system_menu 表

system_menu 是权限控制中最复杂的表,它通过 type 字段将三种资源统一管理:

1. 三种形态 (Type)

类型 值 含义 作用
目录 1 左侧菜单的父节点 归纳子菜单,通常无实际页面(如"系统管理")。
菜单 2 具体的业务页面 点击后跳转路由,加载 Vue 组件(如"用户管理")。
按钮 3 页面内的操作/API 不可见,仅用于控制按钮显示和后端接口鉴权(如"用户新增")。

2. 关键字段详解

  • path (路由地址):

  • 浏览器地址栏显示的 URL 后缀。

  • 拼接规则 :父级 path + 子级 path = 最终访问地址。

  • 例如 :/system (目录) + user (菜单) = /system/user。

  • component (组件路径):

  • 对应前端 Vue 项目中的文件物理路径。

  • 告诉前端路由去哪里加载代码。

  • 例如 :system/user/index 对应 src/views/system/user/index.vue。

  • permission (权限标识) :【核心】

  • 权限的唯一身份证,通常采用 模块:资源:操作 的格式。

  • 例如 :system:user:create(允许在系统模块下创建用户)。

  • 它是连接后端 @PreAuthorize 和前端 v-hasPermi 的唯一暗号。


三、 运行流程:从登录到鉴权

当一个用户登录并进行操作时,权限数据经历了以下流转:

阶段 1:登录 (后端计算与发放)

  1. 用户登录成功。
  2. 后端根据 User -> Role -> Menu 的关联关系,查询出该用户拥有的所有 permission 字符串。
  3. 后端将这个 权限字符串列表 (如 ['system:user:query', 'system:user:create']) 返回给前端。

阶段 2:渲染 (前端存储与展示)

  1. 前端将权限列表存入 Pinia/Vuex 全局 Store 中。
  2. 按钮级控制 :在加载页面时,Vue 自定义指令 v-hasPermi 会工作。
  • 代码 :<el-button v-hasPermi="['system:user:create']">新增</el-button>
  • 逻辑 :去 Store 里找,如果没找到 system:user:create,直接从 DOM 中移除该按钮。

阶段 3:请求 (后端 AOP 拦截与裁决)

  1. 用户点击按钮,发起 API 请求(如 /system/user/create)。
  2. 请求到达 Controller 之前,被 Spring Security 的 AOP 切面 拦截。
  3. 注解生效 :@PreAuthorize("@ss.hasPermission('system:user:create')")。
  • 解析 :调用名为 ss 的 Bean (PermissionService),执行 hasPermission 方法。
  • 判断:再次检查当前用户的权限列表(通常缓存于 Redis 或 SecurityContext)是否包含该字符串。
  1. 结果:
  • 包含 -> 放行(执行业务代码)。
  • 不包含 -> 抛出 403 Forbidden 异常。

四、 代码实战示例

1. 后端 Controller 写法

利用 SpEL 表达式实现细粒度控制:

java 复制代码
@RestController
@RequestMapping("/system/user")
public class UserController {

    @Resource
    private UserService userService;

    // 只有拥有 'system:user:query' 权限才能访问
    @GetMapping("/page")
    @PreAuthorize("@ss.hasPermission('system:user:query')")
    public CommonResult<PageResult<UserRespVO>> getUserPage(@Valid UserPageReqVO reqVO) {
        return success(userService.getUserPage(reqVO));
    }

    // 只有拥有 'system:user:delete' 权限才能访问
    @DeleteMapping("/delete")
    @PreAuthorize("@ss.hasPermission('system:user:delete')")
    public CommonResult<Boolean> deleteUser(@RequestParam("id") Long id) {
        userService.deleteUser(id);
        return success(true);
    }
}

2. 前端 Vue 写法

利用自定义指令控制显隐:

html 复制代码
<template>
  <el-button 
    type="primary" 
    plain 
    icon="el-icon-plus"
    v-hasPermi="['system:user:create']"
    @click="handleAdd"
  >
    新增
  </el-button>
</template>

菜单表 (system_menu) 的三大"脊梁"字段

在 RBAC 权限体系中,system_menu 表不仅存储了权限数据,更承载了 前端路由生成 与 页面渲染 的重任。其中,parent_id、path、component 这三个字段构成了菜单系统的核心逻辑闭环。

1. parent_id:构建无限层级 (The Skeleton)

这是实现树形结构 的关键字段,采用经典的 邻接表 (Adjacency List) 设计模式。

  • 含义:记录当前菜单的父节点 ID。

  • 逻辑:

  • 0:代表根节点(一级菜单/目录)。

  • 非0:代表子节点,挂载在对应的父 ID 下。

  • 作用 :后端通过递归算法将扁平的数据库记录转化为树形结构(Tree),前端据此渲染出层级分明的侧边栏菜单。

2. path:定义访问地址 (The URL)

这是 Vue Router 的路由标识,决定了浏览器地址栏显示什么 URL。

  • 含义:路由访问路径。

  • 拼接规则 :前端路由通常采用嵌套模式,最终访问地址 = 父级 Path + 子级 Path。

  • 目录 (Type=1) :通常以 / 开头,作为模块前缀(如 /system)。

  • 菜单 (Type=2) :通常是纯字符串,作为具体页面的后缀(如 user)。

  • 示例 :当用户点击"用户管理"时,浏览器地址栏变为 /system/user。

3. component:映射代码文件 (The Content)

这是连接路由 与代码的桥梁,决定了页面具体加载哪个 Vue 文件。

  • 含义 :前端 Vue 组件的物理文件路径(相对于 src/views/)。
  • 关键用法:
  • 目录 :通常配置为 Layout。这代表加载系统的标准布局框架(包含侧边栏、顶栏、面包屑),子菜单内容将渲染在 Layout 的"坑位" (<router-view>) 中。
  • 菜单 :配置为具体的 Vue 文件路径。例如 system/user/index,对应前端工程中的 src/views/system/user/index.vue 文件。
相关推荐
扶风ff4 小时前
新品知识更新太快?用练题簿在线刷题,安排企业培训的小测与复盘
前端·学习·小程序
对空六课4 小时前
支持注意力分析的热力图工具有哪些?
前端·数据库·数据分析
Csvn5 小时前
Vue3 响应式与编译:依赖收集如何升级为节点级靶向更新
前端
星栈6 小时前
pnpm 12 升级实测
前端·javascript
Sirens.7 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
Ai-_Man7 小时前
您您这可以把Microsofat Copilot的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑·copilot
苏supper8 小时前
Spring Boot多环境配置与打包运行
spring boot·后端·spring
特创数字科技8 小时前
一个纯本地运行的图片处理工具:压缩 / 裁剪 / 九宫格 / 圆角 / 滤镜 / 拼图 / 水印,终生使用
前端
IT_陈寒9 小时前
Vue的v-if和v-for混用居然是个天坑
前端·人工智能·后端
天衍四九-9 小时前
【无标题】
前端·spring boot·mysql·nginx·docker