基于 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_idpathcomponent 这三个字段构成了菜单系统的核心逻辑闭环。

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 文件。
相关推荐
TAEHENGV2 小时前
关于应用模块 Cordova 与 OpenHarmony 混合开发实战
android·javascript·数据库
资深低代码开发平台专家2 小时前
MicroQuickJS:为极致资源而生的嵌入式JavaScript革命
开发语言·javascript·ecmascript
未来之窗软件服务2 小时前
幽冥大陆(六十七) PHP5.x SSL 文字加密—东方仙盟古法结界
服务器·前端·ssl·仙盟创梦ide·东方仙盟
计算机毕设指导62 小时前
基于微信小程序的智慧社区娱乐服务管理系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·娱乐
nnsix2 小时前
【C#】HttpPost请求 - Query参数 - URL编码方法
java·javascript·c#
小北方城市网2 小时前
第 10 课:Node.js 后端企业级进阶 —— 任务管理系统后端优化与功能增强(续)
大数据·前端·vue.js·ai·性能优化·node.js
华仔啊2 小时前
JavaScript 有哪些数据类型?它们在内存里是怎么存的?
前端·javascript
我有一棵树2 小时前
淘宝 npm 镜像与 CDN 加速链路解析:不只是 Registry,更是分层静态加速架构
前端·架构·npm
zhousenshan2 小时前
vue3基础知识100问
前端·vue.js