From 8278b65777d8249c0c1d29987f91dd39928dcf39 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 13 Dec 2021 09:27:46 +0800 Subject: [PATCH] 重构 Dept 数据权限逻辑,统一收到 yudao-spring-boot-starter-data-permission 包下 --- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java | 173 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java | 21 --------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java | 37 ------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java | 88 ---------------------------------------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.http | 3 ++- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/config/SysDataPermissionConfiguration.java | 25 +++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/package-info.java | 4 ++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysPermissionService.java | 3 ++- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysPermissionServiceImpl.java | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- yudao-framework/yudao-spring-boot-starter-data-permission/pom.xml | 7 +++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java | 45 --------------------------------------------- yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java | 34 ++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/package-info.java | 6 ++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleCustomizer.java | 20 ++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java | 22 ++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/dto/DeptDataPermissionRespDTO.java | 35 +++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories | 3 ++- yudao-framework/yudao-spring-boot-starter-tenant/pom.xml | 5 ----- 20 files changed, 447 insertions(+), 375 deletions(-) delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/config/SysDataPermissionConfiguration.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/package-info.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleCustomizer.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java create mode 100644 yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/dto/DeptDataPermissionRespDTO.java diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java deleted file mode 100644 index ed5c2b9..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java +++ /dev/null @@ -1,173 +0,0 @@ -package cn.iocoder.yudao.adminserver.framework.datapermission.core.rule; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.DeptDataPermissionService; -import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.expression.Alias; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.LongValue; -import net.sf.jsqlparser.expression.operators.conditional.OrExpression; -import net.sf.jsqlparser.expression.operators.relational.EqualsTo; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.expression.operators.relational.InExpression; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * 基于部门的 {@link DataPermissionRule} 数据权限规则实现 - * - * 注意,使用 DeptDataPermissionRule 时,需要保证表中有 dept_id 部门编号的字段,可自定义。 - * - * 实际业务场景下,会存在一个经典的问题?当用户修改部门时,冗余的 dept_id 是否需要修改? - * 1. 一般情况下,dept_id 不进行修改,则会导致用户看到之前的数据。【yudao-admin-server 采用该方案】 - * 2. 部分情况下,希望该用户还是能看到之前的数据,则有两种方式解决:【需要你改造该 DeptDataPermissionRule 的实现代码】 - * 1)编写洗数据的脚本,将 dept_id 修改成新部门的编号;【建议】 - * 最终过滤条件是 WHERE dept_id = ? - * 2)洗数据的话,可能涉及的数据量较大,也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号; - * 最终过滤条件是 WHERE user_id IN (?, ?, ? ...) - * 3)想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤; - * 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...) - * - * @author 芋道源码 - */ -@AllArgsConstructor -@Slf4j -public class DeptDataPermissionRule implements DataPermissionRule { - - private static final String DEPT_COLUMN_NAME = "dept_id"; - private static final String USER_COLUMN_NAME = "user_id"; - - private final DeptDataPermissionService deptDataPermissionService; - - /** - * 基于部门的表字段配置 - * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 - * - * key:表名 - * value:字段名 - */ - private final Map DEPT_TABLE_CONFIG = new HashMap<>(); - /** - * 基于用户的表字段配置 - * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 - * - * key:表名 - * value:字段名 - */ - private final Map USER_TABLE_CONFIG = new HashMap<>(); - /** - * 所有表名,是 {@link #DEPT_TABLE_CONFIG} 和 {@link #USER_TABLE_CONFIG} 的合集 - */ - private final Set TABLE_NAMES = new HashSet<>(); - - @Override - public Set getTableNames() { - return TABLE_NAMES; - } - - @Override - public Expression getExpression(String tableName, Alias tableAlias) { - // 只有有登陆用户的情况下,才进行数据权限的处理 - LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); - if (loginUser == null) { - return null; - } - - // 获得数据权限 - DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser); - if (deptDataPermission == null) { - log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); - return null; - } - - // 情况一,如果是 ALL 可查看全部,则无需拼接条件 - if (deptDataPermission.getAll()) { - return null; - } - - // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 - if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) - && Boolean.FALSE.equals(deptDataPermission.getSelf())) { - return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 - } - - // 情况三,拼接 Dept 和 User 的条件,最后组合 - Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); - Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); - if (deptExpression == null && userExpression == null) { - log.error("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", - JsonUtils.toJsonString(loginUser), tableName, tableAlias, JsonUtils.toJsonString(deptDataPermission)); - throw new NullPointerException(String.format("LoginUser(%d) tableName(%s) tableAlias(%s) 构建的条件为空", - loginUser.getId(), tableName, tableAlias.getName())); - } - if (deptExpression == null) { - return userExpression; - } - if (userExpression == null) { - return deptExpression; - } - // 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE dept_id IN ? OR user_id = ? - return new OrExpression(deptExpression, userExpression); - } - - private Expression buildDeptExpression(String tableName, Alias tableAlias, Set deptIds) { - // 如果不存在配置,则无需作为条件 - String columnName = DEPT_TABLE_CONFIG.get(tableName); - if (StrUtil.isEmpty(columnName)) { - return null; - } - // 拼接条件 - return new InExpression(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), - new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new))); - } - - private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) { - // 如果不查看自己,则无需作为条件 - if (Boolean.FALSE.equals(self)) { - return null; - } - String columnName = USER_TABLE_CONFIG.get(tableName); - if (StrUtil.isEmpty(columnName)) { - return null; - } - // 拼接条件 - return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId)); - } - - // ==================== 添加配置 ==================== - - public void addDeptTableConfig(Class entityClass) { - addDeptTableConfig(entityClass, DEPT_COLUMN_NAME); - } - - public void addDeptTableConfig(Class entityClass, String columnName) { - String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); - DEPT_TABLE_CONFIG.put(tableName, columnName); - TABLE_NAMES.add(tableName); - } - - public void addUserTableConfig(Class entityClass) { - addUserTableConfig(entityClass, DEPT_COLUMN_NAME); - } - - public void addUserTableConfig(Class entityClass, String columnName) { - String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); - USER_TABLE_CONFIG.put(tableName, columnName); - TABLE_NAMES.add(tableName); - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java deleted file mode 100644 index c7e4443..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.adminserver.framework.datapermission.core.service; - -import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.security.core.LoginUser; - -/** - * 基于部门的数据权限 Service 接口 - * - * @author 芋道源码 - */ -public interface DeptDataPermissionService { - - /** - * 获得登陆用户的部门数据权限 - * - * @param loginUser 登陆用户 - * @return 部门数据权限 - */ - DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser); - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java deleted file mode 100644 index 3aa3aba..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto; - -import lombok.Data; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * 部门的数据权限 Response DTO - * - * @author 芋道源码 - */ -@Data -public class DeptDataPermissionRespDTO { - - /** - * 是否可查看全部数据 - */ - private Boolean all; - /** - * 是否可查看自己的数据 - */ - private Boolean self; - /** - * 可查看的部门编号数组 - */ - private Set deptIds; - - public DeptDataPermissionRespDTO() { - this.all = false; - this.self = false; - this.deptIds = new HashSet<>(); - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java deleted file mode 100644 index b02c7e2..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -package cn.iocoder.yudao.adminserver.framework.datapermission.core.service.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.DeptDataPermissionService; -import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO; -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; -import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; -import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; -import java.util.Objects; - -/** - * 基于部门的数据权限 Service 实现类 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Slf4j -public class DeptDataPermissionServiceImpl implements DeptDataPermissionService { - - /** - * LoginUser 的 Context 缓存 Key - */ - private static final String CONTEXT_KEY = DeptDataPermissionServiceImpl.class.getSimpleName(); - - private final SysRoleService roleService; - private final SysDeptService deptService; - - @Override - public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) { - // 判断是否 context 已经缓存 - DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); - if (result != null) { - return result; - } - - // 创建 DeptDataPermissionRespDTO 对象 - result = new DeptDataPermissionRespDTO(); - List roles = roleService.getRolesFromCache(loginUser.getRoleIds()); - for (SysRoleDO role : roles) { - // 为空时,跳过 - if (role.getDataScope() == null) { - continue; - } - // 情况一,ALL - if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) { - result.setAll(true); - continue; - } - // 情况二,DEPT_CUSTOM - if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) { - CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); - continue; - } - // 情况三,DEPT_ONLY - if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { - CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId()); - continue; - } - // 情况四,DEPT_DEPT_AND_CHILD - if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { - List depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true); - CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, SysDeptDO::getId)); - continue; - } - // 情况五,SELF - if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) { - result.setSelf(true); - continue; - } - // 未知情况,error log 即可 - log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result)); - } - - // 添加到缓存,并返回 - loginUser.setContext(CONTEXT_KEY, result); - return null; - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.http b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.http index 8728375..ce138af 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.http +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.http @@ -1,3 +1,4 @@ ### 请求 /system/user/page 接口 => 没有权限 GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10 -Authorization: Bearer test104 # 使用测试账号 +Authorization: Bearer test1 # 使用测试账号 +tenant-id: 1 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/config/SysDataPermissionConfiguration.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/config/SysDataPermissionConfiguration.java new file mode 100644 index 0000000..20f2e16 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/config/SysDataPermissionConfiguration.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission.config; + +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO; +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; +import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * system 模块的数据权限 Configuration + * + * @author 芋道源码 + */ +@Configuration +public class SysDataPermissionConfiguration { + + @Bean + public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() { + return rule -> { + rule.addDeptColumn(SysUserDO.class); + rule.addDeptColumn(SysDeptDO.class, "id"); + }; + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/package-info.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/package-info.java new file mode 100644 index 0000000..cdd6173 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/datapermission/package-info.java @@ -0,0 +1,4 @@ +/** + * system 模块的数据权限配置 + */ +package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysPermissionService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysPermissionService.java index e159f95..883a11f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysPermissionService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysPermissionService.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.system.service.permission; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; import cn.iocoder.yudao.framework.security.core.service.SecurityPermissionFrameworkService; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; import org.springframework.lang.Nullable; @@ -15,7 +16,7 @@ import java.util.Set; * * @author 芋道源码 */ -public interface SysPermissionService extends SecurityPermissionFrameworkService { +public interface SysPermissionService extends SecurityPermissionFrameworkService, DeptDataPermissionFrameworkService { /** * 初始化权限的本地缓存 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysPermissionServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysPermissionServiceImpl.java index b4eb2cb..dd4d3be 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysPermissionServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysPermissionServiceImpl.java @@ -3,19 +3,25 @@ package cn.iocoder.yudao.adminserver.modules.system.service.permission.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysRoleMenuMapper; -import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysUserRoleMapper; +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleMenuDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysUserRoleDO; +import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysRoleMenuMapper; +import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysUserRoleMapper; import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysPermissionProducer; +import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysMenuService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -40,6 +46,11 @@ import java.util.*; public class SysPermissionServiceImpl implements SysPermissionService { /** + * LoginUser 的 Context 缓存 Key + */ + private static final String CONTEXT_KEY = SysPermissionServiceImpl.class.getSimpleName(); + + /** * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 */ @@ -75,6 +86,8 @@ public class SysPermissionServiceImpl implements SysPermissionService { private SysRoleService roleService; @Resource private SysMenuService menuService; + @Resource + private SysDeptService deptService; @Resource private SysPermissionProducer permissionProducer; @@ -329,4 +342,58 @@ public class SysPermissionServiceImpl implements SysPermissionService { return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); } + @Override + public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) { + // 判断是否 context 已经缓存 + DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); + if (result != null) { + return result; + } + + // 创建 DeptDataPermissionRespDTO 对象 + result = new DeptDataPermissionRespDTO(); + List roles = roleService.getRolesFromCache(loginUser.getRoleIds()); + for (SysRoleDO role : roles) { + // 为空时,跳过 + if (role.getDataScope() == null) { + continue; + } + // 情况一,ALL + if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) { + result.setAll(true); + continue; + } + // 情况二,DEPT_CUSTOM + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) { + CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); + // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。 + // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉 + CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId()); + continue; + } + // 情况三,DEPT_ONLY + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { + CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId()); + continue; + } + // 情况四,DEPT_DEPT_AND_CHILD + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { + List depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true); + CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, SysDeptDO::getId)); + continue; + } + // 情况五,SELF + if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) { + result.setSelf(true); + continue; + } + // 未知情况,error log 即可 + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result)); + } + + // 添加到缓存,并返回 + loginUser.setContext(CONTEXT_KEY, result); + return result; + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/pom.xml b/yudao-framework/yudao-spring-boot-starter-data-permission/pom.xml index fac3234..15b0615 100644 --- a/yudao-framework/yudao-spring-boot-starter-data-permission/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/pom.xml @@ -21,6 +21,13 @@ yudao-common + + + cn.iocoder.boot + yudao-spring-boot-starter-security + true + + cn.iocoder.boot diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java deleted file mode 100644 index 44bd502..0000000 --- a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.framework.datapermission.config; - -import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionAnnotationAdvisor; -import cn.iocoder.yudao.framework.datapermission.core.db.DataPermissionDatabaseInterceptor; -import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; -import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; -import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; -import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.List; - -/** - * 数据全新啊的自动配置类 - * - * @author 芋道源码 - */ -@Configuration -public class DataPermissionAutoConfiguration { - - @Bean - public DataPermissionRuleFactory dataPermissionRuleFactory(List rules) { - return new DataPermissionRuleFactoryImpl(rules); - } - - @Bean - public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(MybatisPlusInterceptor interceptor, - List rules) { - // 创建 DataPermissionDatabaseInterceptor 拦截器 - DataPermissionRuleFactory ruleFactory = dataPermissionRuleFactory(rules); - DataPermissionDatabaseInterceptor inner = new DataPermissionDatabaseInterceptor(ruleFactory); - // 添加到 interceptor 中 - // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定 - MyBatisUtils.addInterceptor(interceptor, inner, 0); - return inner; - } - - @Bean - public DataPermissionAnnotationAdvisor dataPermissionAnnotationAdvisor() { - return new DataPermissionAnnotationAdvisor(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java new file mode 100644 index 0000000..609e8a3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.framework.datapermission.config; + +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionAnnotationAdvisor; +import cn.iocoder.yudao.framework.datapermission.core.db.DataPermissionDatabaseInterceptor; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +/** + * 数据全新啊的自动配置类 + * + * @author 芋道源码 + */ +@Configuration +public class YudaoDataPermissionAutoConfiguration { + + @Bean + public DataPermissionRuleFactory dataPermissionRuleFactory(List rules) { + return new DataPermissionRuleFactoryImpl(rules); + } + + @Bean + public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(MybatisPlusInterceptor interceptor, + List rules) { + // 创建 DataPermissionDatabaseInterceptor 拦截器 + DataPermissionRuleFactory ruleFactory = dataPermissionRuleFactory(rules); + DataPermissionDatabaseInterceptor inner = new DataPermissionDatabaseInterceptor(ruleFactory); + // 添加到 interceptor 中 + // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定 + MyBatisUtils.addInterceptor(interceptor, inner, 0); + return inner; + } + + @Bean + public DataPermissionAnnotationAdvisor dataPermissionAnnotationAdvisor() { + return new DataPermissionAnnotationAdvisor(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java new file mode 100644 index 0000000..b66c176 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.datapermission.config; + +import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +/** + * 基于部门的数据权限 AutoConfiguration + * + * @author 芋道源码 + */ +@Configuration +@ConditionalOnClass(LoginUser.class) +@ConditionalOnBean(value = {DeptDataPermissionFrameworkService.class, DeptDataPermissionRuleCustomizer.class}) +public class YudaoDeptDataPermissionAutoConfiguration { + + @Bean + public DeptDataPermissionRule deptDataPermissionRule(DeptDataPermissionFrameworkService service, + List customizers) { + // 创建 DeptDataPermissionRule 对象 + DeptDataPermissionRule rule = new DeptDataPermissionRule(service); + // 补全表配置 + customizers.forEach(customizer -> customizer.customize(rule)); + return rule; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/package-info.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/package-info.java new file mode 100644 index 0000000..20daa85 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/package-info.java @@ -0,0 +1,6 @@ +/** + * 基于部门的数据权限规则 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.datapermission.core.dept; diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java new file mode 100644 index 0000000..0bbb1ba --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java @@ -0,0 +1,173 @@ +package cn.iocoder.yudao.framework.datapermission.core.dept.rule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 基于部门的 {@link DataPermissionRule} 数据权限规则实现 + * + * 注意,使用 DeptDataPermissionRule 时,需要保证表中有 dept_id 部门编号的字段,可自定义。 + * + * 实际业务场景下,会存在一个经典的问题?当用户修改部门时,冗余的 dept_id 是否需要修改? + * 1. 一般情况下,dept_id 不进行修改,则会导致用户看到之前的数据。【yudao-admin-server 采用该方案】 + * 2. 部分情况下,希望该用户还是能看到之前的数据,则有两种方式解决:【需要你改造该 DeptDataPermissionRule 的实现代码】 + * 1)编写洗数据的脚本,将 dept_id 修改成新部门的编号;【建议】 + * 最终过滤条件是 WHERE dept_id = ? + * 2)洗数据的话,可能涉及的数据量较大,也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号; + * 最终过滤条件是 WHERE user_id IN (?, ?, ? ...) + * 3)想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤; + * 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...) + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Slf4j +public class DeptDataPermissionRule implements DataPermissionRule { + + private static final String DEPT_COLUMN_NAME = "dept_id"; + private static final String USER_COLUMN_NAME = "user_id"; + + private final DeptDataPermissionFrameworkService deptDataPermissionService; + + /** + * 基于部门的表字段配置 + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 + * + * key:表名 + * value:字段名 + */ + private final Map deptColumns = new HashMap<>(); + /** + * 基于用户的表字段配置 + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 + * + * key:表名 + * value:字段名 + */ + private final Map userColumns = new HashMap<>(); + /** + * 所有表名,是 {@link #deptColumns} 和 {@link #userColumns} 的合集 + */ + private final Set TABLE_NAMES = new HashSet<>(); + + @Override + public Set getTableNames() { + return TABLE_NAMES; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + // 只有有登陆用户的情况下,才进行数据权限的处理 + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + return null; + } + + // 获得数据权限 + DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser); + if (deptDataPermission == null) { + log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); + return null; + } + + // 情况一,如果是 ALL 可查看全部,则无需拼接条件 + if (deptDataPermission.getAll()) { + return null; + } + + // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 + if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) + && Boolean.FALSE.equals(deptDataPermission.getSelf())) { + return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 + } + + // 情况三,拼接 Dept 和 User 的条件,最后组合 + Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); + Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); + if (deptExpression == null && userExpression == null) { + log.error("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", + JsonUtils.toJsonString(loginUser), tableName, tableAlias, JsonUtils.toJsonString(deptDataPermission)); + throw new NullPointerException(String.format("LoginUser(%d) tableName(%s) tableAlias(%s) 构建的条件为空", + loginUser.getId(), tableName, tableAlias.getName())); + } + if (deptExpression == null) { + return userExpression; + } + if (userExpression == null) { + return deptExpression; + } + // 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE dept_id IN ? OR user_id = ? + return new OrExpression(deptExpression, userExpression); + } + + private Expression buildDeptExpression(String tableName, Alias tableAlias, Set deptIds) { + // 如果不存在配置,则无需作为条件 + String columnName = deptColumns.get(tableName); + if (StrUtil.isEmpty(columnName)) { + return null; + } + // 拼接条件 + return new InExpression(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), + new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new))); + } + + private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) { + // 如果不查看自己,则无需作为条件 + if (Boolean.FALSE.equals(self)) { + return null; + } + String columnName = userColumns.get(tableName); + if (StrUtil.isEmpty(columnName)) { + return null; + } + // 拼接条件 + return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId)); + } + + // ==================== 添加配置 ==================== + + public void addDeptColumn(Class entityClass) { + addDeptColumn(entityClass, DEPT_COLUMN_NAME); + } + + public void addDeptColumn(Class entityClass, String columnName) { + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); + deptColumns.put(tableName, columnName); + TABLE_NAMES.add(tableName); + } + + public void addUserColumn(Class entityClass) { + addUserColumn(entityClass, USER_COLUMN_NAME); + } + + public void addUserColumn(Class entityClass, String columnName) { + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); + userColumns.put(tableName, columnName); + TABLE_NAMES.add(tableName); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleCustomizer.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleCustomizer.java new file mode 100644 index 0000000..5341ee5 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleCustomizer.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.datapermission.core.dept.rule; + +/** + * {@link DeptDataPermissionRule} 的自定义配置接口 + * + * @author 芋道源码 + */ +@FunctionalInterface +public interface DeptDataPermissionRuleCustomizer { + + /** + * 自定义该权限规则 + * 1. 调用 {@link DeptDataPermissionRule#addDeptColumn(Class, String)} 方法,配置基于 dept_id 的过滤规则 + * 2. 调用 {@link DeptDataPermissionRule#addUserColumn(Class, String)} 方法,配置基于 user_id 的过滤规则 + * + * @param rule 权限规则 + */ + void customize(DeptDataPermissionRule rule); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java new file mode 100644 index 0000000..3ee6167 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.datapermission.core.dept.service; + +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.security.core.LoginUser; + +/** + * 基于部门的数据权限 Framework Service 接口 + * 目前的实现类是 SysPermissionServiceImpl 类 + * + * @author 芋道源码 + */ +public interface DeptDataPermissionFrameworkService { + + /** + * 获得登陆用户的部门数据权限 + * + * @param loginUser 登陆用户 + * @return 部门数据权限 + */ + DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/dto/DeptDataPermissionRespDTO.java b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/dto/DeptDataPermissionRespDTO.java new file mode 100644 index 0000000..897fb22 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/dto/DeptDataPermissionRespDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.datapermission.core.dept.service.dto; + +import lombok.Data; + +import java.util.HashSet; +import java.util.Set; + +/** + * 部门的数据权限 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DeptDataPermissionRespDTO { + + /** + * 是否可查看全部数据 + */ + private Boolean all; + /** + * 是否可查看自己的数据 + */ + private Boolean self; + /** + * 可查看的部门编号数组 + */ + private Set deptIds; + + public DeptDataPermissionRespDTO() { + this.all = false; + this.self = false; + this.deptIds = new HashSet<>(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories index 51af3a2..1a4c029 100644 --- a/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories +++ b/yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - cn.iocoder.yudao.framework.datapermission.config.DataPermissionAutoConfiguration + cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionAutoConfiguration,\ + cn.iocoder.yudao.framework.datapermission.config.YudaoDeptDataPermissionAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml b/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml index e7d81f3..f7010cf 100644 --- a/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml @@ -23,11 +23,6 @@ - org.springframework.boot - spring-boot-starter-web - - - cn.iocoder.boot yudao-spring-boot-starter-security -- libgit2 0.21.4