尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

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

RuoYi-Cloud-Plus 数据权限实现原理解析
📅 发布时间:2026/6/20 13:38:03

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 存储上下文信息,避免重复查询

相关新闻

  • 详细介绍:JavaScript学习笔记(十五):ES6模板字符串使用指南
  • [HZOI] CSP-S模拟38 赛后总结
  • 集合常见操作示例

最新新闻

  • 零投诉零纠纷!2026沈阳黄金回收标杆品牌合扬实力认证 - 奢侈品交易观察员
  • 夸克网盘链接解析直链链接_在线解析网盘链接
  • 【图像隐写】基于DWT、SVD和扩频技术混合可见-隐形水印系统(将彩色标志和强大的隐藏水印嵌入图像中附Matlab代码
  • Qwen3-VL技术报告实操解剖:双塔对齐、动态桥接与工业级微调指南
  • HDRI转立方体贴图终极指南:3步让3D场景光照真实感翻倍
  • 5分钟搞定M3U8视频下载:免费工具让加密视频轻松保存

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号