fix bugs
This commit is contained in:
33
blade-starter-datascope/pom.xml
Normal file
33
blade-starter-datascope/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-datascope</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.annotation;
|
||||
|
||||
import org.springblade.core.datascope.constant.DataScopeConstant;
|
||||
import org.springblade.core.datascope.enums.DataScopeEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限定义
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface DataAuth {
|
||||
|
||||
/**
|
||||
* 资源编号
|
||||
*/
|
||||
String code() default "";
|
||||
|
||||
/**
|
||||
* 数据权限对应字段
|
||||
*/
|
||||
String column() default DataScopeConstant.DEFAULT_COLUMN;
|
||||
|
||||
/**
|
||||
* 数据权限规则
|
||||
*/
|
||||
DataScopeEnum type() default DataScopeEnum.ALL;
|
||||
|
||||
/**
|
||||
* 可见字段
|
||||
*/
|
||||
String field() default "*";
|
||||
|
||||
/**
|
||||
* 数据权限规则值域
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.datascope.handler.BladeDataScopeHandler;
|
||||
import org.springblade.core.datascope.handler.BladeScopeModelHandler;
|
||||
import org.springblade.core.datascope.handler.DataScopeHandler;
|
||||
import org.springblade.core.datascope.handler.ScopeModelHandler;
|
||||
import org.springblade.core.datascope.interceptor.DataScopeInterceptor;
|
||||
import org.springblade.core.datascope.props.DataScopeProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* 数据权限配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@AllArgsConstructor
|
||||
@EnableConfigurationProperties(DataScopeProperties.class)
|
||||
public class DataScopeConfiguration {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ScopeModelHandler.class)
|
||||
public ScopeModelHandler scopeModelHandler() {
|
||||
return new BladeScopeModelHandler(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(ScopeModelHandler.class)
|
||||
@ConditionalOnMissingBean(DataScopeHandler.class)
|
||||
public DataScopeHandler dataScopeHandler(ScopeModelHandler scopeModelHandler) {
|
||||
return new BladeDataScopeHandler(scopeModelHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(DataScopeHandler.class)
|
||||
@ConditionalOnMissingBean(DataScopeInterceptor.class)
|
||||
public DataScopeInterceptor interceptor(DataScopeHandler dataScopeHandler, DataScopeProperties dataScopeProperties) {
|
||||
return new DataScopeInterceptor(dataScopeHandler, dataScopeProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.constant;
|
||||
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* 数据权限常量
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface DataScopeConstant {
|
||||
|
||||
String DEFAULT_COLUMN = "create_dept";
|
||||
|
||||
/**
|
||||
* 获取部门数据
|
||||
*/
|
||||
String DATA_BY_DEPT = "select id from blade_dept where ancestors like concat(concat('%', ?),'%') and is_deleted = 0";
|
||||
|
||||
/**
|
||||
* 根据resourceCode获取数据权限配置
|
||||
*/
|
||||
String DATA_BY_CODE = "select resource_code, scope_column, scope_field, scope_type, scope_value from blade_scope_data where resource_code = ?";
|
||||
|
||||
/**
|
||||
* 根据mapperId获取数据权限配置
|
||||
*
|
||||
* @param size 数量
|
||||
* @return String
|
||||
*/
|
||||
static String dataByMapper(int size) {
|
||||
return "select resource_code, scope_column, scope_field, scope_type, scope_value from blade_scope_data where scope_class = ? and id in (select scope_id from blade_role_scope where scope_category = 1 and role_id in (" + buildHolder(size) + "))";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Sql占位符
|
||||
*
|
||||
* @param size 数量
|
||||
* @return String
|
||||
*/
|
||||
static String buildHolder(int size) {
|
||||
StringBuilder builder = StringUtil.builder();
|
||||
for (int i = 0; i < size; i++) {
|
||||
builder.append("?,");
|
||||
}
|
||||
return StringUtil.removeSuffix(builder.toString(), ",");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 数据权限类型
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DataScopeEnum {
|
||||
/**
|
||||
* 全部数据
|
||||
*/
|
||||
ALL(1, "全部"),
|
||||
|
||||
/**
|
||||
* 本人可见
|
||||
*/
|
||||
OWN(2, "本人可见"),
|
||||
|
||||
/**
|
||||
* 所在机构可见
|
||||
*/
|
||||
OWN_DEPT(3, "所在机构可见"),
|
||||
|
||||
/**
|
||||
* 所在机构及子级可见
|
||||
*/
|
||||
OWN_DEPT_CHILD(4, "所在机构及子级可见"),
|
||||
|
||||
/**
|
||||
* 自定义
|
||||
*/
|
||||
CUSTOM(5, "自定义");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final int type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public static DataScopeEnum of(Integer dataScopeType) {
|
||||
return Optional.ofNullable(dataScopeType)
|
||||
.flatMap(type -> Arrays.stream(DataScopeEnum.values())
|
||||
.filter(scopeTypeEnum -> scopeTypeEnum.type == dataScopeType)
|
||||
.findFirst())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.exception;
|
||||
|
||||
/**
|
||||
* 数据权限异常
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
public class DataScopeException extends RuntimeException {
|
||||
|
||||
public DataScopeException() {
|
||||
}
|
||||
|
||||
public DataScopeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DataScopeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.datascope.enums.DataScopeEnum;
|
||||
import org.springblade.core.datascope.model.DataScopeModel;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springblade.core.tool.constant.RoleConstant;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.PlaceholderUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 默认数据权限规则
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BladeDataScopeHandler implements DataScopeHandler {
|
||||
|
||||
private final ScopeModelHandler scopeModelHandler;
|
||||
|
||||
@Override
|
||||
public String sqlCondition(String mapperId, DataScopeModel dataScope, BladeUser bladeUser, String originalSql) {
|
||||
|
||||
//数据权限资源编号
|
||||
String code = dataScope.getResourceCode();
|
||||
|
||||
//根据mapperId从数据库中获取对应模型
|
||||
DataScopeModel dataScopeDb = scopeModelHandler.getDataScopeByMapper(mapperId, bladeUser.getRoleId());
|
||||
|
||||
//mapperId配置未取到则从数据库中根据资源编号获取
|
||||
if (dataScopeDb == null && StringUtil.isNotBlank(code)) {
|
||||
dataScopeDb = scopeModelHandler.getDataScopeByCode(code);
|
||||
}
|
||||
|
||||
//未从数据库找到对应配置则采用默认
|
||||
dataScope = (dataScopeDb != null) ? dataScopeDb : dataScope;
|
||||
|
||||
//判断数据权限类型并组装对应Sql
|
||||
Integer scopeRule = Objects.requireNonNull(dataScope).getScopeType();
|
||||
DataScopeEnum scopeTypeEnum = DataScopeEnum.of(scopeRule);
|
||||
List<Long> ids = new ArrayList<>();
|
||||
String whereSql = "where scope.{} in ({})";
|
||||
if (DataScopeEnum.ALL == scopeTypeEnum || StringUtil.containsAny(bladeUser.getRoleName(), RoleConstant.ADMINISTRATOR)) {
|
||||
return null;
|
||||
} else if (DataScopeEnum.CUSTOM == scopeTypeEnum) {
|
||||
whereSql = PlaceholderUtil.getDefaultResolver().resolveByMap(dataScope.getScopeValue(), BeanUtil.toMap(bladeUser));
|
||||
} else if (DataScopeEnum.OWN == scopeTypeEnum) {
|
||||
ids.add(bladeUser.getUserId());
|
||||
} else if (DataScopeEnum.OWN_DEPT == scopeTypeEnum) {
|
||||
ids.addAll(Func.toLongList(bladeUser.getDeptId()));
|
||||
} else if (DataScopeEnum.OWN_DEPT_CHILD == scopeTypeEnum) {
|
||||
List<Long> deptIds = Func.toLongList(bladeUser.getDeptId());
|
||||
ids.addAll(deptIds);
|
||||
deptIds.forEach(deptId -> {
|
||||
List<Long> deptIdList = scopeModelHandler.getDeptAncestors(deptId);
|
||||
ids.addAll(deptIdList);
|
||||
});
|
||||
}
|
||||
return StringUtil.format("select {} from ({}) scope " + whereSql, Func.toStr(dataScope.getScopeField(), "*"), originalSql, dataScope.getScopeColumn(), StringUtil.join(ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.cache.utils.CacheUtil;
|
||||
import org.springblade.core.datascope.constant.DataScopeConstant;
|
||||
import org.springblade.core.datascope.model.DataScopeModel;
|
||||
import org.springblade.core.tool.utils.CollectionUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
|
||||
|
||||
/**
|
||||
* BladeScopeModelHandler
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BladeScopeModelHandler implements ScopeModelHandler {
|
||||
|
||||
private static final String SCOPE_CACHE_CODE = "dataScope:code:";
|
||||
private static final String SCOPE_CACHE_CLASS = "dataScope:class:";
|
||||
private static final String DEPT_CACHE_ANCESTORS = "dept:ancestors:";
|
||||
private static final DataScopeModel SEARCHED_DATA_SCOPE_MODEL = new DataScopeModel(Boolean.TRUE);
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
/**
|
||||
* 获取数据权限
|
||||
*
|
||||
* @param mapperId 数据权限mapperId
|
||||
* @param roleId 用户角色集合
|
||||
* @return DataScopeModel
|
||||
*/
|
||||
@Override
|
||||
public DataScopeModel getDataScopeByMapper(String mapperId, String roleId) {
|
||||
List<Object> args = new ArrayList<>(Collections.singletonList(mapperId));
|
||||
List<Long> roleIds = Func.toLongList(roleId);
|
||||
args.addAll(roleIds);
|
||||
// 增加searched字段防止未配置的参数重复读库导致缓存击穿
|
||||
// 后续若有新增配置则会清空缓存重新加载
|
||||
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, DataScopeModel.class, Boolean.FALSE);
|
||||
if (dataScope == null || !dataScope.getSearched()) {
|
||||
List<DataScopeModel> list = jdbcTemplate.query(DataScopeConstant.dataByMapper(roleIds.size()), args.toArray(), new BeanPropertyRowMapper<>(DataScopeModel.class));
|
||||
if (CollectionUtil.isNotEmpty(list)) {
|
||||
dataScope = list.iterator().next();
|
||||
dataScope.setSearched(Boolean.TRUE);
|
||||
} else {
|
||||
dataScope = SEARCHED_DATA_SCOPE_MODEL;
|
||||
}
|
||||
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, dataScope, Boolean.FALSE);
|
||||
}
|
||||
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限
|
||||
*
|
||||
* @param code 数据权限资源编号
|
||||
* @return DataScopeModel
|
||||
*/
|
||||
@Override
|
||||
public DataScopeModel getDataScopeByCode(String code) {
|
||||
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, code, DataScopeModel.class, Boolean.FALSE);
|
||||
// 增加searched字段防止未配置的参数重复读库导致缓存击穿
|
||||
// 后续若有新增配置则会清空缓存重新加载
|
||||
if (dataScope == null || !dataScope.getSearched()) {
|
||||
List<DataScopeModel> list = jdbcTemplate.query(DataScopeConstant.DATA_BY_CODE, new Object[]{code}, new BeanPropertyRowMapper<>(DataScopeModel.class));
|
||||
if (CollectionUtil.isNotEmpty(list)) {
|
||||
dataScope = list.iterator().next();
|
||||
dataScope.setSearched(Boolean.TRUE);
|
||||
} else {
|
||||
dataScope = SEARCHED_DATA_SCOPE_MODEL;
|
||||
}
|
||||
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, code, dataScope, Boolean.FALSE);
|
||||
}
|
||||
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门子级
|
||||
*
|
||||
* @param deptId 部门id
|
||||
* @return deptIds
|
||||
*/
|
||||
@Override
|
||||
public List<Long> getDeptAncestors(Long deptId) {
|
||||
List ancestors = CacheUtil.get(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, List.class);
|
||||
if (CollectionUtil.isEmpty(ancestors)) {
|
||||
ancestors = jdbcTemplate.queryForList(DataScopeConstant.DATA_BY_DEPT, new Object[]{deptId}, Long.class);
|
||||
CacheUtil.put(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, ancestors);
|
||||
}
|
||||
return ancestors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.handler;
|
||||
|
||||
import org.springblade.core.datascope.model.DataScopeModel;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
|
||||
/**
|
||||
* 数据权限规则
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface DataScopeHandler {
|
||||
|
||||
/**
|
||||
* 获取过滤sql
|
||||
*
|
||||
* @param mapperId 数据查询类
|
||||
* @param dataScope 数据权限类
|
||||
* @param bladeUser 当前用户信息
|
||||
* @param originalSql 原始Sql
|
||||
* @return sql
|
||||
*/
|
||||
String sqlCondition(String mapperId, DataScopeModel dataScope, BladeUser bladeUser, String originalSql);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.handler;
|
||||
|
||||
import org.springblade.core.datascope.model.DataScopeModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 获取数据权限模型统一接口
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface ScopeModelHandler {
|
||||
|
||||
/**
|
||||
* 获取数据权限
|
||||
*
|
||||
* @param mapperId 数据权限mapperId
|
||||
* @param roleId 用户角色集合
|
||||
* @return DataScopeModel
|
||||
*/
|
||||
DataScopeModel getDataScopeByMapper(String mapperId, String roleId);
|
||||
|
||||
/**
|
||||
* 获取数据权限
|
||||
*
|
||||
* @param code 数据权限资源编号
|
||||
* @return DataScopeModel
|
||||
*/
|
||||
DataScopeModel getDataScopeByCode(String code);
|
||||
|
||||
/**
|
||||
* 获取部门子级
|
||||
*
|
||||
* @param deptId 部门id
|
||||
* @return deptIds
|
||||
*/
|
||||
List<Long> getDeptAncestors(Long deptId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.interceptor;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.executor.Executor;
|
||||
import org.apache.ibatis.mapping.BoundSql;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlCommandType;
|
||||
import org.apache.ibatis.mapping.StatementType;
|
||||
import org.apache.ibatis.session.ResultHandler;
|
||||
import org.apache.ibatis.session.RowBounds;
|
||||
import org.springblade.core.datascope.annotation.DataAuth;
|
||||
import org.springblade.core.datascope.handler.DataScopeHandler;
|
||||
import org.springblade.core.datascope.model.DataScopeModel;
|
||||
import org.springblade.core.datascope.props.DataScopeProperties;
|
||||
import org.springblade.core.mp.intercept.QueryInterceptor;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.utils.ClassUtil;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
||||
/**
|
||||
* mybatis 数据权限拦截器
|
||||
*
|
||||
* @author L.cm, Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
public class DataScopeInterceptor implements QueryInterceptor {
|
||||
|
||||
private final ConcurrentMap<String, DataAuth> dataAuthMap = new ConcurrentHashMap<>(8);
|
||||
|
||||
private final DataScopeHandler dataScopeHandler;
|
||||
private final DataScopeProperties dataScopeProperties;
|
||||
|
||||
@Override
|
||||
public void intercept(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||
//未启用则放行
|
||||
if (!dataScopeProperties.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//未取到用户则放行
|
||||
BladeUser bladeUser = AuthUtil.getUser();
|
||||
if (bladeUser == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SqlCommandType.SELECT != ms.getSqlCommandType() || StatementType.CALLABLE == ms.getStatementType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String originalSql = boundSql.getSql();
|
||||
|
||||
//查找注解中包含DataAuth类型的参数
|
||||
DataAuth dataAuth = findDataAuthAnnotation(ms);
|
||||
|
||||
//注解为空并且数据权限方法名未匹配到,则放行
|
||||
String mapperId = ms.getId();
|
||||
String className = mapperId.substring(0, mapperId.lastIndexOf(StringPool.DOT));
|
||||
String mapperName = ClassUtil.getShortName(className);
|
||||
String methodName = mapperId.substring(mapperId.lastIndexOf(StringPool.DOT) + 1);
|
||||
boolean mapperSkip = dataScopeProperties.getMapperKey().stream().noneMatch(methodName::contains)
|
||||
|| dataScopeProperties.getMapperExclude().stream().anyMatch(mapperName::contains);
|
||||
if (dataAuth == null && mapperSkip) {
|
||||
return;
|
||||
}
|
||||
|
||||
//创建数据权限模型
|
||||
DataScopeModel dataScope = new DataScopeModel();
|
||||
|
||||
//若注解不为空,则配置注解项
|
||||
if (dataAuth != null) {
|
||||
dataScope.setResourceCode(dataAuth.code());
|
||||
dataScope.setScopeColumn(dataAuth.column());
|
||||
dataScope.setScopeType(dataAuth.type().getType());
|
||||
dataScope.setScopeField(dataAuth.field());
|
||||
dataScope.setScopeValue(dataAuth.value());
|
||||
}
|
||||
|
||||
//获取数据权限规则对应的筛选Sql
|
||||
String sqlCondition = dataScopeHandler.sqlCondition(mapperId, dataScope, bladeUser, originalSql);
|
||||
if (!StringUtil.isBlank(sqlCondition)) {
|
||||
PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
|
||||
mpBoundSql.sql(sqlCondition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限注解信息
|
||||
*
|
||||
* @param mappedStatement mappedStatement
|
||||
* @return DataAuth
|
||||
*/
|
||||
private DataAuth findDataAuthAnnotation(MappedStatement mappedStatement) {
|
||||
String id = mappedStatement.getId();
|
||||
return dataAuthMap.computeIfAbsent(id, (key) -> {
|
||||
String className = key.substring(0, key.lastIndexOf(StringPool.DOT));
|
||||
String mapperBean = StringUtil.firstCharToLower(ClassUtil.getShortName(className));
|
||||
Object mapper = SpringUtil.getBean(mapperBean);
|
||||
String methodName = key.substring(key.lastIndexOf(StringPool.DOT) + 1);
|
||||
Class<?>[] interfaces = ClassUtil.getAllInterfaces(mapper);
|
||||
for (Class<?> mapperInterface : interfaces) {
|
||||
for (Method method : mapperInterface.getDeclaredMethods()) {
|
||||
if (methodName.equals(method.getName()) && method.isAnnotationPresent(DataAuth.class)) {
|
||||
return method.getAnnotation(DataAuth.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springblade.core.datascope.constant.DataScopeConstant;
|
||||
import org.springblade.core.datascope.enums.DataScopeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 数据权限实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DataScopeModel implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造器创建
|
||||
*/
|
||||
public DataScopeModel(Boolean searched) {
|
||||
this.searched = searched;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已查询
|
||||
*/
|
||||
private Boolean searched = Boolean.FALSE;
|
||||
/**
|
||||
* 资源编号
|
||||
*/
|
||||
private String resourceCode;
|
||||
/**
|
||||
* 数据权限字段
|
||||
*/
|
||||
private String scopeColumn = DataScopeConstant.DEFAULT_COLUMN;
|
||||
/**
|
||||
* 数据权限规则
|
||||
*/
|
||||
private Integer scopeType = DataScopeEnum.ALL.getType();
|
||||
/**
|
||||
* 可见字段
|
||||
*/
|
||||
private String scopeField;
|
||||
/**
|
||||
* 数据权限规则值
|
||||
*/
|
||||
private String scopeValue;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.datascope.props;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据权限参数配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "blade.data-scope")
|
||||
public class DataScopeProperties {
|
||||
|
||||
/**
|
||||
* 开启数据权限
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* mapper方法匹配关键字
|
||||
*/
|
||||
private List<String> mapperKey = Arrays.asList("page", "Page", "list", "List");
|
||||
|
||||
/**
|
||||
* mapper过滤
|
||||
*/
|
||||
private List<String> mapperExclude = Collections.singletonList("FlowMapper");
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user