RuoYi-Cloud-Plus 数据权限实现原理解析

news/2025/10/25 21:42:42/文章来源:https://www.cnblogs.com/xiaochenNN/p/19166016

RuoYi-Cloud-Plus 数据权限实现原理解析

什么是数据权限?

数据权限是控制用户能够访问哪些数据的权限机制。在实际业务场景中,我们经常遇到这样的需求:

  • 普通员工只能查看自己创建的数据
  • 部门经理可以查看本部门所有员工的数据
  • 总经理可以查看全公司的数据

这种按照用户角色和组织结构控制数据访问范围的机制就是数据权限控制。

RuoYi-Cloud-Plus 数据权限设计思路

RuoYi-Cloud-Plus 采用了 AOP(面向切面编程)+ MyBatis 拦截器的组合方式来实现数据权限控制:

  1. 通过自定义注解标记需要进行数据权限控制的方法
  2. 利用 AOP 在方法执行前设置权限上下文
  3. 通过 MyBatis 拦截器拦截 SQL 语句并动态添加过滤条件

核心组件解析

1. 数据权限注解

RuoYi-Cloud-Plus 定义了两个核心注解:

@DataPermission 注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {DataColumn[] value();     // 数据权限配置数组String joinStr() default ""; // 权限拼接标识符
}

@DataPermission 注解用于标记需要进行数据权限控制的方法或类,其中:

  • value:包含一个或多个 @DataColumn 注解,定义数据权限的详细配置
  • joinStr:指定多个数据权限条件之间的连接方式(AND 或 OR)

@DataColumn 注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataColumn {String[] key() default "deptName";    // 占位符关键字String[] value() default "dept_id";   // 占位符替换值String permission() default "";       // 权限标识符
}

@DataColumn 注解用于定义数据权限的占位符和替换值:

  • key:SQL 模板中的占位符关键字
  • value:实际数据库表中的字段名
  • permission:权限标识符,拥有此权限的用户将不受数据权限限制

2. AOP 切面处理

AOP 切面由三个核心组件构成:

DataPermissionPointcut - 切点定义

public class DataPermissionPointcut extends StaticMethodMatcherPointcut {@Overridepublic boolean matches(Method method, Class<?> targetClass) {// 匹配带有 @DataPermission 注解的方法if (method.isAnnotationPresent(DataPermission.class)) {return true;}// 处理 JDK 动态代理的情况Class<?> targetClassRef = targetClass;if (Proxy.isProxyClass(targetClassRef)) {targetClassRef = targetClass.getInterfaces()[0];}return targetClassRef.isAnnotationPresent(DataPermission.class);}
}

DataPermissionAdvice - 通知逻辑

public class DataPermissionAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Object target = invocation.getThis();Method method = invocation.getMethod();Object[] args = invocation.getArguments();// 设置权限注解到上下文DataPermissionHelper.setPermission(getDataPermissionAnnotation(target, method, args));try {// 执行目标方法return invocation.proceed();} finally {// 清除权限注解DataPermissionHelper.removePermission();}}
}

DataPermissionPointcutAdvisor - 切面组合

public class DataPermissionPointcutAdvisor extends AbstractPointcutAdvisor {private final Advice advice;private final Pointcut pointcut;public DataPermissionPointcutAdvisor() {this.advice = new DataPermissionAdvice();this.pointcut = new DataPermissionPointcut();}@Overridepublic Pointcut getPointcut() {return this.pointcut;}@Overridepublic Advice getAdvice() {return this.advice;}
}

3. 权限上下文管理

DataPermissionHelper 负责管理权限上下文,使用 ThreadLocal 存储当前线程的权限信息:

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataPermissionHelper {// 使用 ThreadLocal 存储当前线程的权限注解private static final ThreadLocal<DataPermission> PERMISSION_CACHE = new ThreadLocal<>();// 设置权限注解public static void setPermission(DataPermission dataPermission) {PERMISSION_CACHE.set(dataPermission);}// 获取权限注解public static DataPermission getPermission() {return PERMISSION_CACHE.get();}// 清除权限注解public static void removePermission() {PERMISSION_CACHE.remove();}
}

4. MyBatis 拦截器

MyBatis 拦截器负责在 SQL 执行前动态添加数据权限过滤条件:

public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor {private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler();@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {// 检查是否需要忽略数据权限处理if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {return;}// 检查是否缺少有效的数据权限注解if (dataPermissionHandler.invalid()) {return;}// 解析并修改 SQLPluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));}
}

数据权限处理流程

1. 方法调用阶段

当执行带有 @DataPermission 注解的方法时:

  1. AOP 拦截器捕获方法调用
  2. 从方法或类上获取 @DataPermission 注解信息
  3. 将注解信息存储到 ThreadLocal
  4. 执行目标方法(通常是 MyBatis Mapper 方法)
  5. 方法执行完成后,清除 ThreadLocal 中的注解信息

2. SQL 拦截阶段

当 MyBatis 执行 SQL 语句时:

  1. MyBatis 拦截器捕获 SQL 执行请求
  2. ThreadLocal 中获取权限注解信息
  3. 根据当前用户角色和权限范围构建过滤条件
  4. 将过滤条件动态添加到 SQL 中

3. 权限条件构建

权限条件构建过程如下:

  1. 获取当前登录用户信息
  2. 判断用户是否为超级管理员(超级管理员不受数据权限限制)
  3. 根据用户角色获取数据范围类型
  4. 使用 SpEL 表达式解析权限模板
  5. 替换占位符生成最终的 SQL 过滤条件

实际使用示例

基本使用

// 在 Mapper 接口上使用数据权限注解
@DataPermission({@DataColumn(key = "deptName", value = "dept_id"),@DataColumn(key = "userName", value = "user_id")
})
public interface SysUserMapper {List<SysUser> selectUserList(SysUser user);
}

假设当前用户是部门经理,属于部门 ID 为 1、2、3 的部门,用户 ID 为 1001,生成的 SQL 可能类似于:

SELECT * FROM sys_user WHERE (dept_id IN (1, 2, 3) OR user_id = 1001)

使用 joinStr 控制连接方式

@DataPermission(value = {@DataColumn(key = "deptName", value = "dept_id"),@DataColumn(key = "userName", value = "user_id")
}, joinStr = "AND")
public interface SysUserMapper {List<SysUser> selectUserList(SysUser user);
}

使用 joinStr = "AND" 后,生成的 SQL 可能类似于:

SELECT * FROM sys_user WHERE (dept_id IN (1, 2, 3) AND user_id = 1001)

使用权限标识符

@DataPermission({@DataColumn(key = "deptName", value = "dept_id"),@DataColumn(key = "userName", value = "user_id", permission = "system:user:all")
})
public interface SysUserMapper {List<SysUser> selectUserList(SysUser user);
}

如果用户拥有 "system:user:all" 权限,则不受数据权限限制,生成的 SQL 不会添加额外的过滤条件。

joinStr 参数详解

在 @DataPermission 注解中,joinStr 属性用于指定多个数据权限条件之间的连接方式:

  • 不指定 joinStr:查询操作默认使用 "OR",更新/删除操作默认使用 "AND"
  • 指定 joinStr = "AND":多个条件使用 AND 连接
  • 指定 joinStr = "OR":多个条件使用 OR 连接

总结

RuoYi-Cloud-Plus 的数据权限实现具有以下优势:

  1. 无侵入性:通过注解方式实现,业务代码无需修改
  2. 灵活性:支持在方法和类级别使用,可以定义多个数据列的过滤规则
  3. 可扩展性:通过 SpEL 表达式支持复杂的权限逻辑
  4. 高性能:使用 ThreadLocal 存储上下文信息,避免重复查询

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/946451.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细介绍:JavaScript学习笔记(十五):ES6模板字符串使用指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Python毕业设计实例-基于python养老社区的查询预约架构(源码+LW+部署文档+全bao+远程调试+代码讲解等)

Python毕业设计实例-基于python养老社区的查询预约架构(源码+LW+部署文档+全bao+远程调试+代码讲解等)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: blo…

第5天(中等题 滑动窗口、逆向思维)

打卡第五天 两道中等题题1423.可获得的最大点数思路: n 表示数组总数,先算出数组总和,用滑动窗口选出剩下连续(n-k)个数的最小和,用总和-剩余数最小和,即得拿走数的最大值.(逆向思维,正难则反) 耗时≈一小时 明天继续

Meet in the middle 学习笔记

由于蒟蒻在模拟赛写 DFS 挂掉了,所以来学 Meet in the middle 。 「引入」 Meet in the middle 算法没有正式译名,常见的翻译为「折半搜索」、「双向搜索」或「中途相遇」,以下称折半搜索。 它适用于输入数据较小,…

华为堡垒机

1、打开了VM虚拟机,导入相关的.ovf文件2、导入成功之后,不要直接开机。添加1块硬盘、网卡后再开机 3、开机之后,默认的用户为coreshell,密码为Admin@123 初次登录会提示更改密码密码: 请更改控制台密码,因为首次登…

[HZOI] CSP-S模拟38 赛后总结

不予置评[HZOI] CSP-S模拟38 赛后总结 不予置评 T1:最小生成树(tree) #include<bits/stdc++.h> #define lid (id << 1) #define rid (id << 1 | 1) #define Blue_Archive return 0 #define int lo…

集合常见操作示例

集合(Set)是数学和编程中常用的数据结构,用于存储唯一元素(无重复值)。以下是集合的常见操作及其示例,涵盖数学集合和编程实现(以Python为例):1. 创建集合数学表示:A = {1, 2, 3} Python示例:A = {1, 2, 3}…

深入解析:港大和字节携手打造WorldWeaver:以统一建模方案整合感知条件,为长视频生成领域带来质量与一致性双重飞跃。

深入解析:港大和字节携手打造WorldWeaver:以统一建模方案整合感知条件,为长视频生成领域带来质量与一致性双重飞跃。pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importa…

虚拟机下 安装 ubuntu 18.04

VMware虚拟机中安装Ubuntu18.04(linux发行版)【超详细图文教程】_vmware安装ubuntu18.04-CSDN博客

MinIO快速入门

MinIO快速入门1. MinIO 介绍 MinIO 是全球领先的对象存储先锋,目前在全世界有数百万的用户。高性能 ,在标准硬件上,读/写速度上高达 183GB/秒和 171GB/秒,拥有更高的吞吐量和更低的延迟 可扩展性 ,为对象存储带来…

实用指南:【代码的暴力美学】-- C语言基础编程题_1

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

路径规划算法学习Day2:广度优先搜索算法(BFS)

路径规划算法学习Day2:广度优先搜索算法(BFS)前言 如果我想要用一群人来走迷宫,人的总数确定,从一点出发,每到一个节点就分出去一个人,那么我就可以根据要探索的层的数量来判断实际所需要的人数,应该是呈现一个…

集合与列表有何不同的使用场景,如何选择?

在Python中,集合(set)和列表(list)是两种不同的数据结构,各自有独特的使用场景和特性。选择它们的关键在于是否需要唯一性、顺序性或高效的查找/修改操作。以下是详细对比和选择建议:1. 核心特性对比特性 列表(…

102302147傅乐宜作业1

1.用requests和BeautifulSoup库方法爬取大学排名信息 内容 核心代码:点击查看代码 import urllib.request from bs4 import BeautifulSoupurl = http://www.shanghairanking.cn/rankings/bcur/2020 response = urllib…

完整教程:ros_control 中 hardware_interface 教程

完整教程:ros_control 中 hardware_interface 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

飞牛NAS的SSL证书过期,又开启了强制HTTPS,进不去界面修改SSL怎么办? - 详解

飞牛NAS的SSL证书过期,又开启了强制HTTPS,进不去界面修改SSL怎么办? - 详解2025-10-25 21:21 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow…

多表查询-练习

-- 多表查询-练习1 -- 1.查询员工的姓名、年龄、职位、部门信息。(隐式内连接) select e.name,e.age,e.job,d.* from emp e ,dept d where e.dept_id = d.id; -- 2.查询年龄小于30岁的员工姓名、年龄、职位、部门信息。…

多智能体大模型在农业中的应用研究与展望

研究意义 首次系统提出“多智能体 大语言模型”在农业中的完整技术框架,为“耕-种-管-收”全流程智能化、无人化提供理论+落地路线。 技术框架• 多智能体系统(MAS)=“角色分工 + 动态协作 + 分布式决策”。 • 大…

嵌入式基础作业--第七周--IIC协议采集温湿度与OLED显示

任务一. 解释什么是“软件I2C”和“硬件I2C” 根据野火教材第23章"IC--读写EEPROM"的内容,详细解释软件I2C和硬件I2C的概念和区别: I2C总线基础 I2C(Inter-Integrated Circuit)是一种两线式串行总线,包…

Nature子刊 | 基于生物学信息的神经网络

机器学习模型在多组学数据中的应用常常需要在预测准确性与生物学可解释性之间进行权衡。一种新兴的深度学习架构通过结构化地编码生物学知识,以提升预测能力和可解释性。然而,更广泛地采用这种架构仍面临着机遇与挑战…