1. 修复回滚父子角色功能时错误的代码逻辑,补全单元测试用例
2. 新增支持切换后业务菜单查询需限定只查询该公司业务数据能力
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.yudao.framework.datapermission.config;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.company.CompanyDataPermissionRule;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.company.CompanyDataPermissionRuleCustomizer;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 基于部门的数据权限 AutoConfiguration
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass(LoginUser.class)
|
||||
@ConditionalOnBean(value = {CompanyDataPermissionRuleCustomizer.class})
|
||||
public class YudaoCompanyDataPermissionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public CompanyDataPermissionRule companyDataPermissionRule(List<CompanyDataPermissionRuleCustomizer> customizers) {
|
||||
|
||||
// 创建 CompanyDataPermissionRule 对象
|
||||
CompanyDataPermissionRule rule = new CompanyDataPermissionRule();
|
||||
// 补全表配置
|
||||
customizers.forEach(customizer -> customizer.customize(rule));
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,7 @@ import java.util.List;
|
||||
public class YudaoDeptDataPermissionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public DeptDataPermissionRule deptDataPermissionRule(PermissionCommonApi permissionApi,
|
||||
List<DeptDataPermissionRuleCustomizer> customizers) {
|
||||
public DeptDataPermissionRule deptDataPermissionRule(PermissionCommonApi permissionApi, List<DeptDataPermissionRuleCustomizer> customizers) {
|
||||
// Cloud 专属逻辑:优先使用本地的 PermissionApi 实现类,而不是 Feign 调用
|
||||
// 原因:在创建租户时,租户还没创建好,导致 Feign 调用获取数据权限时,报“租户不存在”的错误
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.iocoder.yudao.framework.datapermission.core.rule.company;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserCompanyId;
|
||||
|
||||
/**
|
||||
* 基于公司类型部门的 {@link DataPermissionRule} 数据权限规则实现
|
||||
* 注意,使用 CompanyDataPermissionRule 时,需要保证表中有 company_id 公司编号的字段,可自定义。
|
||||
*
|
||||
* @author chenbowen
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class CompanyDataPermissionRule implements DataPermissionRule {
|
||||
static final Expression EXPRESSION_NULL = new NullValue();
|
||||
|
||||
/**
|
||||
* 基于部门的表字段配置
|
||||
* 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。
|
||||
* key:表名
|
||||
* value:字段名
|
||||
*/
|
||||
private final Map<String, String> companyColumns = new HashMap<>();
|
||||
/**
|
||||
* 所有表名,是 {@link #companyColumns} 的合集
|
||||
*/
|
||||
private final Set<String> TABLE_NAMES = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public Set<String> getTableNames() {
|
||||
return TABLE_NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getExpression(String tableName, Alias tableAlias) {
|
||||
// 业务拼接 Company 的条件
|
||||
if (getLoginUserCompanyId() == null) {
|
||||
// 如果没有登录用户的公司编号,则不需要拼接条件
|
||||
return null;
|
||||
}
|
||||
Expression companyExpression = buildCompanyExpression(tableName, tableAlias, Collections.singleton(getLoginUserCompanyId()));
|
||||
return Objects.requireNonNullElse(companyExpression, EXPRESSION_NULL);
|
||||
}
|
||||
|
||||
private Expression buildCompanyExpression(String tableName, Alias tableAlias, Set<Long> companyIds) {
|
||||
// 如果不存在配置,则无需作为条件
|
||||
String columnName = companyColumns.get(tableName);
|
||||
if (StrUtil.isEmpty(columnName)) {
|
||||
return null;
|
||||
}
|
||||
// 如果为空,则无条件
|
||||
if (CollUtil.isEmpty(companyIds)) {
|
||||
return null;
|
||||
}
|
||||
// 拼接条件
|
||||
return new InExpression(MyBatisUtils.buildColumn(tableName, tableAlias, columnName),
|
||||
// Parenthesis 的目的,是提供 (1,2,3) 的 () 左右括号
|
||||
new ParenthesedExpressionList<>(new ExpressionList<>(CollectionUtils.convertList(companyIds, LongValue::new))));
|
||||
}
|
||||
|
||||
public void addCompanyColumn(String tableName, String columnName) {
|
||||
companyColumns.put(tableName, columnName);
|
||||
TABLE_NAMES.add(tableName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.framework.datapermission.core.rule.company;
|
||||
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule;
|
||||
|
||||
/**
|
||||
* {@link DeptDataPermissionRule} 的自定义配置接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CompanyDataPermissionRuleCustomizer {
|
||||
|
||||
/**
|
||||
* 自定义该权限规则
|
||||
* 1. 调用 {@link CompanyDataPermissionRule#addCompanyColumn(Class, String)} 方法,配置基于 dept_id 的过滤规则
|
||||
*
|
||||
* @param rule 权限规则
|
||||
*/
|
||||
void customize(CompanyDataPermissionRule rule);
|
||||
|
||||
}
|
||||
@@ -121,6 +121,11 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
||||
// 添加到上下文中,避免重复计算
|
||||
loginUser.setContext(CONTEXT_KEY, deptDataPermission);
|
||||
}
|
||||
// 如果不归属任何部门,且无可查询所有部门的权限,提示当前用户未关联任何部门
|
||||
// if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && !deptDataPermission.getAll()) {
|
||||
// log.error("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 未关联任何部门]", JsonUtils.toJsonString(loginUser), tableName, tableAlias.getName(), JsonUtils.toJsonString(deptDataPermission));
|
||||
// throw new NullPointerException("当前登录用户未关联任何部门,请先联系管理员进行部门关联");
|
||||
// }
|
||||
// 如果开启了公司上下文,且缓存的公司编号不等于 CompanyContextHolder 的公司编号,则更新缓存
|
||||
if(!CompanyContextHolder.isIgnore()) {
|
||||
Long companyId = CompanyContextHolder.getCompanyId();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionAutoConfiguration
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDeptDataPermissionAutoConfiguration
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoCompanyDataPermissionAutoConfiguration
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionRpcAutoConfiguration
|
||||
|
||||
Reference in New Issue
Block a user