This commit is contained in:
2025-11-28 16:23:32 +08:00
commit a9e0e16c29
826 changed files with 89805 additions and 0 deletions

View 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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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