重构 Dept 数据权限逻辑,统一收到 yudao-spring-boot-starter-data-permission 包下

pull/2/head
YunaiV 2021-12-13 09:27:46 +08:00
parent 986cb72421
commit 8278b65777
17 changed files with 213 additions and 141 deletions

View File

@ -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);
}

View File

@ -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<SysRoleDO> 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<SysDeptDO> 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;
}
}

View File

@ -1,3 +1,4 @@
### 请求 /system/user/page 接口 => 没有权限 ### 请求 /system/user/page 接口 => 没有权限
GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10 GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10
Authorization: Bearer test104 # 使用测试账号 Authorization: Bearer test1 # 使用测试账号
tenant-id: 1

View File

@ -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");
};
}
}

View File

@ -0,0 +1,4 @@
/**
* system
*/
package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission;

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.system.service.permission; 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.framework.security.core.service.SecurityPermissionFrameworkService;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -15,7 +16,7 @@ import java.util.Set;
* *
* @author * @author
*/ */
public interface SysPermissionService extends SecurityPermissionFrameworkService { public interface SysPermissionService extends SecurityPermissionFrameworkService, DeptDataPermissionFrameworkService {
/** /**
* *

View File

@ -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.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
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.permission.SysMenuDO; 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.SysRoleDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleMenuDO; 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.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.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.SysMenuService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; 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.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 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.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -39,6 +45,11 @@ import java.util.*;
@Slf4j @Slf4j
public class SysPermissionServiceImpl implements SysPermissionService { public class SysPermissionServiceImpl implements SysPermissionService {
/**
* LoginUser Context Key
*/
private static final String CONTEXT_KEY = SysPermissionServiceImpl.class.getSimpleName();
/** /**
* {@link #schedulePeriodicRefresh()} * {@link #schedulePeriodicRefresh()}
* Redis Pub/Sub * Redis Pub/Sub
@ -75,6 +86,8 @@ public class SysPermissionServiceImpl implements SysPermissionService {
private SysRoleService roleService; private SysRoleService roleService;
@Resource @Resource
private SysMenuService menuService; private SysMenuService menuService;
@Resource
private SysDeptService deptService;
@Resource @Resource
private SysPermissionProducer permissionProducer; private SysPermissionProducer permissionProducer;
@ -329,4 +342,58 @@ public class SysPermissionServiceImpl implements SysPermissionService {
return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); 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<SysRoleDO> 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<SysDeptDO> 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;
}
} }

View File

@ -21,6 +21,13 @@
<artifactId>yudao-common</artifactId> <artifactId>yudao-common</artifactId>
</dependency> </dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<optional>true</optional> <!-- 可选,如果使用 DeptDataPermissionRule 必须提供 -->
</dependency>
<!-- DB 相关 --> <!-- DB 相关 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>

View File

@ -18,7 +18,7 @@ import java.util.List;
* @author * @author
*/ */
@Configuration @Configuration
public class DataPermissionAutoConfiguration { public class YudaoDataPermissionAutoConfiguration {
@Bean @Bean
public DataPermissionRuleFactory dataPermissionRuleFactory(List<DataPermissionRule> rules) { public DataPermissionRuleFactory dataPermissionRuleFactory(List<DataPermissionRule> rules) {

View File

@ -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<DeptDataPermissionRuleCustomizer> customizers) {
// 创建 DeptDataPermissionRule 对象
DeptDataPermissionRule rule = new DeptDataPermissionRule(service);
// 补全表配置
customizers.forEach(customizer -> customizer.customize(rule));
return rule;
}
}

View File

@ -0,0 +1,6 @@
/**
*
*
* @author
*/
package cn.iocoder.yudao.framework.datapermission.core.dept;

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.framework.datapermission.core.rule; package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.DeptDataPermissionService; import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; 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.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
@ -51,7 +51,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
private static final String DEPT_COLUMN_NAME = "dept_id"; private static final String DEPT_COLUMN_NAME = "dept_id";
private static final String USER_COLUMN_NAME = "user_id"; private static final String USER_COLUMN_NAME = "user_id";
private final DeptDataPermissionService deptDataPermissionService; private final DeptDataPermissionFrameworkService deptDataPermissionService;
/** /**
* *
@ -60,7 +60,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
* key * key
* value * value
*/ */
private final Map<String, String> DEPT_TABLE_CONFIG = new HashMap<>(); private final Map<String, String> deptColumns = new HashMap<>();
/** /**
* *
* dept_id * dept_id
@ -68,9 +68,9 @@ public class DeptDataPermissionRule implements DataPermissionRule {
* key * key
* value * value
*/ */
private final Map<String, String> USER_TABLE_CONFIG = new HashMap<>(); private final Map<String, String> userColumns = new HashMap<>();
/** /**
* {@link #DEPT_TABLE_CONFIG} {@link #USER_TABLE_CONFIG} * {@link #deptColumns} {@link #userColumns}
*/ */
private final Set<String> TABLE_NAMES = new HashSet<>(); private final Set<String> TABLE_NAMES = new HashSet<>();
@ -126,7 +126,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) { private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) {
// 如果不存在配置,则无需作为条件 // 如果不存在配置,则无需作为条件
String columnName = DEPT_TABLE_CONFIG.get(tableName); String columnName = deptColumns.get(tableName);
if (StrUtil.isEmpty(columnName)) { if (StrUtil.isEmpty(columnName)) {
return null; return null;
} }
@ -140,7 +140,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
if (Boolean.FALSE.equals(self)) { if (Boolean.FALSE.equals(self)) {
return null; return null;
} }
String columnName = USER_TABLE_CONFIG.get(tableName); String columnName = userColumns.get(tableName);
if (StrUtil.isEmpty(columnName)) { if (StrUtil.isEmpty(columnName)) {
return null; return null;
} }
@ -150,23 +150,23 @@ public class DeptDataPermissionRule implements DataPermissionRule {
// ==================== 添加配置 ==================== // ==================== 添加配置 ====================
public void addDeptTableConfig(Class<? extends BaseDO> entityClass) { public void addDeptColumn(Class<? extends BaseDO> entityClass) {
addDeptTableConfig(entityClass, DEPT_COLUMN_NAME); addDeptColumn(entityClass, DEPT_COLUMN_NAME);
} }
public void addDeptTableConfig(Class<? extends BaseDO> entityClass, String columnName) { public void addDeptColumn(Class<? extends BaseDO> entityClass, String columnName) {
String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName();
DEPT_TABLE_CONFIG.put(tableName, columnName); deptColumns.put(tableName, columnName);
TABLE_NAMES.add(tableName); TABLE_NAMES.add(tableName);
} }
public void addUserTableConfig(Class<? extends BaseDO> entityClass) { public void addUserColumn(Class<? extends BaseDO> entityClass) {
addUserTableConfig(entityClass, DEPT_COLUMN_NAME); addUserColumn(entityClass, USER_COLUMN_NAME);
} }
public void addUserTableConfig(Class<? extends BaseDO> entityClass, String columnName) { public void addUserColumn(Class<? extends BaseDO> entityClass, String columnName) {
String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName();
USER_TABLE_CONFIG.put(tableName, columnName); userColumns.put(tableName, columnName);
TABLE_NAMES.add(tableName); TABLE_NAMES.add(tableName);
} }

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,10 +1,8 @@
package cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto; package cn.iocoder.yudao.framework.datapermission.core.dept.service.dto;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
/** /**

View File

@ -1,2 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 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

View File

@ -22,11 +22,6 @@
</dependency> </dependency>
<!-- Web 相关 --> <!-- Web 相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId> <artifactId>yudao-spring-boot-starter-security</artifactId>