用户数据权限——基于ruoyi代码分析
一、数据权限实现核心原理
Ruoyi框架通过注解+AOP切面方式实现数据权限控制。核心思想是在SQL执行前动态拼接权限过滤条件,基于用户角色、部门等属性限制数据可见范围。
二、数据权限作用及设置
数据权限设置:

不同角色数据权限不同看到的数据有差别:

三、数据权限后端源码分析
(1) 定义数据权限注解
注解标记:@DataScope
数据权限注解
@DataScope定义在方法上,包含两个关键属性:
deptAlias:部门表别名userAlias:用户表别名@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DataScope { // 部门表的别名(用于SQL拼接) String deptAlias() default ""; // 用户表的别名(用于SQL拼接) String userAlias() default ""; }使用示例:
// SysUserServiceImpl.java 第71行 @DataScope(deptAlias = "d", userAlias = "u") public List<SysUser> selectUserList(SysUser user) { return userMapper.selectUserList(user); }
(2) AOP切面拦截(核心逻辑):
执行时机: 在被
@DataScope注解的方法执行前拦截@Before("@annotation(controllerDataScope)") public void doBefore(JoinPoint point, DataScope controllerDataScope) { clearDataScope(point); // 清空防止注入 handleDataScope(point, controllerDataScope); // 处理数据权限 }处理步骤(核心方法
dataScopeFilter的执行流程:):1.获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser(); SysUser currentUser = loginUser.getUser();2.判断是否超级管理员
超管跳过过滤
if (!currentUser.isAdmin()) { dataScopeFilter(...); }3.遍历用户角色,拼接SQL条件
AOP切面
DataScopeAspect拦截带有@DataScope注解的方法,通过DataPermissionHelper获取当前用户的权限范围。系统内置五种权限类型:
- 全部数据权限(无过滤)
- 自定数据权限(自定义SQL)
- 部门数据权限(仅本部门)
- 部门及以下数据权限(本部门及子部门)
- 仅本人数据权限(当前用户)
for (SysRole role : user.getRoles()) { String dataScope = role.getDataScope(); if (DATA_SCOPE_ALL.equals(dataScope)) { // 全部数据权限:清空条件直接跳出 sqlString = new StringBuilder(); break; } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { // 自定义权限:从 sys_role_dept 获取可访问部门 sqlString.append(" OR d.dept_id IN (SELECT dept_id FROM sys_role_dept WHERE role_id = " + role.getRoleId() + ")"); } else if (DATA_SCOPE_DEPT.equals(dataScope)) { // 本部门权限 sqlString.append(" OR d.dept_id = " + user.getDeptId()); } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { // 本部门及以下权限(利用 ancestors 字段查询子部门) sqlString.append(" OR d.dept_id IN (SELECT dept_id FROM sys_dept WHERE dept_id = " + user.getDeptId() + " or find_in_set(" + user.getDeptId() + ", ancestors))"); } else if (DATA_SCOPE_SELF.equals(dataScope)) { // 仅本人权限 sqlString.append(" OR u.user_id = " + user.getUserId()); } }4.将SQL条件注入到请求参数
BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0]; baseEntity.getParams().put("dataScope", " AND (" + sqlString.substring(4) + ")");
(3)在Service层使用注解
@Override @DataScope(deptAlias = "d", userAlias = "u") // ← 触发AOP拦截 public List<SysUser> selectUserList(SysUser user) { return userMapper.selectUserList(user); // 此时 user.params.dataScope 已注入SQL }
(4)MyBatis动态SQL应用
在
SysUserMapper.xml中:通过${params.dataScope}注入动态生成的权限条件<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult"> SELECT u.user_id, u.user_name, d.dept_name FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id WHERE u.del_flag = '0' <!-- 动态注入数据权限过滤条件 --> ${params.dataScope} </select>最终生成的SQL示例:
SELECT ... FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id WHERE u.del_flag = '0' AND (d.dept_id = 103 OR d.dept_id IN (SELECT dept_id FROM sys_dept WHERE dept_id = 103 or find_in_set(103, ancestors)))
(5)后端API处理
处理数据权限配置请求:
Controller层:
SysRoleController.java@PutMapping("/dataScope") public AjaxResult dataScope(@RequestBody SysRole role) { roleService.checkRoleAllowed(role); roleService.checkRoleDataScope(role.getRoleId()); return toAjax(roleService.authDataScope(role)); }Service层:
SysRoleServiceImpl.java@Transactional public int authDataScope(SysRole role) { // 修改角色的 data_scope 字段 roleMapper.updateRole(role); // 删除旧的角色-部门关联 roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId()); // 新增角色和部门信息(仅当选择"自定义数据权限"时) return insertRoleDept(role); }
四、自定义数据权限控制
步骤1.修改Service层,添加数据权限注解:
在 DeviceInfoServiceImpl 的 selectDeviceInfoList 方法上添加 @DataScope 注解:

步骤2:修改Mapper XML,添加数据权限过滤条件:
在 DeviceInfoMapper.xml 的查询SQL中添加数据权限过滤条件:

步骤3:添加表别名
运行后出现小错误
| 错误 SQL | SELECT count(0) FROM device_info WHERE (d.dept_id = 105) |
说明:
SQL 查询中使用了别名 d(如 d.dept_id)
但在 FROM 子句中 并未给 device_info 表定义别名 d。
因此数据库无法识别 d.dept_id,因为 d 这个别名根本不存在。

若以前端操作



查看实现效果



DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)