添加数据权限SDK
This commit is contained in:
parent
a1fed917e7
commit
1e2393c1c5
33
axzo-common-data-permission/pom.xml
Normal file
33
axzo-common-data-permission/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>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-data-permission</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.karma</groupId>
|
||||
<artifactId>karma-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.axzo.framework.datapermission.annotation;
|
||||
|
||||
import cn.axzo.framework.datapermission.rule.DataPermissionRule;
|
||||
|
||||
/**
|
||||
* 数据权限注解
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/30 17:57
|
||||
*/
|
||||
public @interface DataPermission {
|
||||
boolean enable() default false;
|
||||
|
||||
Class<? extends DataPermissionRule>[] includeRule() default {};
|
||||
|
||||
String bizCode() default "";
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.framework.datapermission.aop;
|
||||
|
||||
import cn.axzo.framework.datapermission.annotation.DataPermission;
|
||||
import cn.axzo.framework.datapermission.config.DataPermissionConfig;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/31 16:37
|
||||
*/
|
||||
public class DataPermissionFilter {
|
||||
|
||||
// 拦截@DataPermission
|
||||
// 设置DataPermissionContext
|
||||
|
||||
}
|
||||
@ -0,0 +1,325 @@
|
||||
package cn.axzo.framework.datapermission.aop;
|
||||
|
||||
import cn.axzo.framework.datapermission.annotation.DataPermission;
|
||||
import cn.axzo.framework.datapermission.context.DataPermissionContextFactory;
|
||||
import cn.axzo.framework.datapermission.context.DataPermissionContextHolder;
|
||||
import cn.axzo.framework.datapermission.rule.DataPermissionRule;
|
||||
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
|
||||
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.NotExpression;
|
||||
import net.sf.jsqlparser.expression.Parenthesis;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.delete.Delete;
|
||||
import net.sf.jsqlparser.statement.select.FromItem;
|
||||
import net.sf.jsqlparser.statement.select.Join;
|
||||
import net.sf.jsqlparser.statement.select.LateralSubSelect;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
import net.sf.jsqlparser.statement.select.Select;
|
||||
import net.sf.jsqlparser.statement.select.SelectBody;
|
||||
import net.sf.jsqlparser.statement.select.SetOperationList;
|
||||
import net.sf.jsqlparser.statement.select.SubJoin;
|
||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
import net.sf.jsqlparser.statement.select.ValuesList;
|
||||
import net.sf.jsqlparser.statement.select.WithItem;
|
||||
import net.sf.jsqlparser.statement.update.Update;
|
||||
import org.apache.ibatis.executor.Executor;
|
||||
import org.apache.ibatis.executor.statement.StatementHandler;
|
||||
import org.apache.ibatis.mapping.BoundSql;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlCommandType;
|
||||
import org.apache.ibatis.session.ResultHandler;
|
||||
import org.apache.ibatis.session.RowBounds;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 参考 #{@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor}
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/31 11:41
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DataPermissionMybatisInterceptor extends JsqlParserSupport implements InnerInterceptor {
|
||||
|
||||
private final DataPermissionContextFactory dataPermissionContextFactory;
|
||||
@Override
|
||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
|
||||
if (!filter()) {
|
||||
return;
|
||||
}
|
||||
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
|
||||
mpBs.sql(parserSingle(mpBs.sql(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||
MappedStatement ms = mpSh.mappedStatement();
|
||||
SqlCommandType sct = ms.getSqlCommandType();
|
||||
// 不管insert
|
||||
if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
||||
if (!filter()) return;
|
||||
if (SqlParserHelper.getSqlParserInfo(ms)) return;
|
||||
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
||||
mpBs.sql(parserMulti(mpBs.sql(), null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSelect(Select select, int index, String sql, Object obj) {
|
||||
processSelectBody(select.getSelectBody());
|
||||
List<WithItem> withItemsList = select.getWithItemsList();
|
||||
if (!CollectionUtils.isEmpty(withItemsList)) {
|
||||
withItemsList.forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processSelectBody(SelectBody selectBody) {
|
||||
if (selectBody == null) {
|
||||
return;
|
||||
}
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
processPlainSelect((PlainSelect) selectBody);
|
||||
} else if (selectBody instanceof WithItem) {
|
||||
WithItem withItem = (WithItem) selectBody;
|
||||
processSelectBody(withItem.getSelectBody());
|
||||
} else {
|
||||
SetOperationList operationList = (SetOperationList) selectBody;
|
||||
if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
|
||||
operationList.getSelects().forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update 语句处理
|
||||
*/
|
||||
@Override
|
||||
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
||||
final Table table = update.getTable();
|
||||
if (!filter()) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
update.setWhere(this.andExpression(table, update.getWhere()));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete 语句处理
|
||||
*/
|
||||
@Override
|
||||
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
||||
if (!filter()) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere()));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete update 语句 where 处理
|
||||
*/
|
||||
protected Expression andExpression(Table table, Expression where) {
|
||||
|
||||
|
||||
DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get();
|
||||
DataPermission dataPermission = dataPermissionContext.getDataPermission();
|
||||
List<DataPermissionRule> byDataPermission = dataPermissionContextFactory.getRuleByDataPermission(dataPermission);
|
||||
Optional<DataPermissionRule> first = byDataPermission.stream().filter(rule -> rule.getTableName().contains(table.getName())).findFirst();
|
||||
if (!first.isPresent()) {
|
||||
return where;
|
||||
}
|
||||
DataPermissionRule dataPermissionRule = first.get();
|
||||
Expression ruleExpression = dataPermissionRule.getExpression(table.getName(), table.getAlias());
|
||||
|
||||
if (null != where) {
|
||||
if (where instanceof OrExpression) {
|
||||
return new AndExpression(ruleExpression, new Parenthesis(where));
|
||||
} else {
|
||||
return new AndExpression(ruleExpression, where);
|
||||
}
|
||||
}
|
||||
return ruleExpression;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 处理 PlainSelect
|
||||
*/
|
||||
protected void processPlainSelect(PlainSelect plainSelect) {
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where);
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
if (filter()) {
|
||||
//#1186 github
|
||||
plainSelect.setWhere(builderExpression(where, fromTable));
|
||||
}
|
||||
} else {
|
||||
processFromItem(fromItem);
|
||||
}
|
||||
List<Join> joins = plainSelect.getJoins();
|
||||
if (joins != null && joins.size() > 0) {
|
||||
joins.forEach(j -> {
|
||||
processJoin(j);
|
||||
processFromItem(j.getRightItem());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理where条件内的子查询
|
||||
* <p>
|
||||
* 支持如下:
|
||||
* 1. in
|
||||
* 2. =
|
||||
* 3. >
|
||||
* 4. <
|
||||
* 5. >=
|
||||
* 6. <=
|
||||
* 7. <>
|
||||
* 8. EXISTS
|
||||
* 9. NOT EXISTS
|
||||
* <p>
|
||||
* 前提条件:
|
||||
* 1. 子查询必须放在小括号中
|
||||
* 2. 子查询一般放在比较操作符的右边
|
||||
*
|
||||
* @param where where 条件
|
||||
*/
|
||||
protected void processWhereSubSelect(Expression where) {
|
||||
if (where == null) {
|
||||
return;
|
||||
}
|
||||
if (where instanceof FromItem) {
|
||||
processFromItem((FromItem) where);
|
||||
return;
|
||||
}
|
||||
if (where.toString().indexOf("SELECT") > 0) {
|
||||
// 有子查询
|
||||
if (where instanceof BinaryExpression) {
|
||||
// 比较符号 , and , or , 等等
|
||||
BinaryExpression expression = (BinaryExpression) where;
|
||||
processWhereSubSelect(expression.getLeftExpression());
|
||||
processWhereSubSelect(expression.getRightExpression());
|
||||
} else if (where instanceof InExpression) {
|
||||
// in
|
||||
InExpression expression = (InExpression) where;
|
||||
ItemsList itemsList = expression.getRightItemsList();
|
||||
if (itemsList instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) itemsList).getSelectBody());
|
||||
}
|
||||
} else if (where instanceof ExistsExpression) {
|
||||
// exists
|
||||
ExistsExpression expression = (ExistsExpression) where;
|
||||
processWhereSubSelect(expression.getRightExpression());
|
||||
} else if (where instanceof NotExpression) {
|
||||
// not exists
|
||||
NotExpression expression = (NotExpression) where;
|
||||
processWhereSubSelect(expression.getExpression());
|
||||
} else if (where instanceof Parenthesis) {
|
||||
Parenthesis expression = (Parenthesis) where;
|
||||
processWhereSubSelect(expression.getExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理子查询等
|
||||
*/
|
||||
protected void processFromItem(FromItem fromItem) {
|
||||
if (fromItem instanceof SubJoin) {
|
||||
SubJoin subJoin = (SubJoin) fromItem;
|
||||
if (subJoin.getJoinList() != null) {
|
||||
subJoin.getJoinList().forEach(this::processJoin);
|
||||
}
|
||||
if (subJoin.getLeft() != null) {
|
||||
processFromItem(subJoin.getLeft());
|
||||
}
|
||||
} else if (fromItem instanceof SubSelect) {
|
||||
SubSelect subSelect = (SubSelect) fromItem;
|
||||
if (subSelect.getSelectBody() != null) {
|
||||
processSelectBody(subSelect.getSelectBody());
|
||||
}
|
||||
} else if (fromItem instanceof ValuesList) {
|
||||
logger.debug("Perform a subquery, if you do not give us feedback");
|
||||
} else if (fromItem instanceof LateralSubSelect) {
|
||||
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
||||
if (lateralSubSelect.getSubSelect() != null) {
|
||||
SubSelect subSelect = lateralSubSelect.getSubSelect();
|
||||
if (subSelect.getSelectBody() != null) {
|
||||
processSelectBody(subSelect.getSelectBody());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理联接语句
|
||||
*/
|
||||
protected void processJoin(Join join) {
|
||||
if (join.getRightItem() instanceof Table) {
|
||||
Table fromTable = (Table) join.getRightItem();
|
||||
if (!filter()) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理条件
|
||||
*/
|
||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||
|
||||
DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get();
|
||||
DataPermission dataPermission = dataPermissionContext.getDataPermission();
|
||||
List<DataPermissionRule> byDataPermission = dataPermissionContextFactory.getRuleByDataPermission(dataPermission);
|
||||
Optional<DataPermissionRule> first = byDataPermission.stream().filter(rule -> rule.getTableName().contains(table.getName())).findFirst();
|
||||
if (!first.isPresent()) {
|
||||
return currentExpression;
|
||||
}
|
||||
DataPermissionRule dataPermissionRule = first.get();
|
||||
Expression ruleExpression = dataPermissionRule.getExpression(table.getName(), table.getAlias());
|
||||
if (currentExpression == null) {
|
||||
return ruleExpression;
|
||||
}
|
||||
if (currentExpression instanceof OrExpression) {
|
||||
return new AndExpression(new Parenthesis(currentExpression), ruleExpression);
|
||||
} else {
|
||||
return new AndExpression(currentExpression, ruleExpression);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private boolean filter() {
|
||||
DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get();
|
||||
if (null == dataPermissionContext|| !dataPermissionContext.getDataPermission().enable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.framework.datapermission.config;
|
||||
|
||||
import cn.axzo.framework.datapermission.aop.DataPermissionMybatisInterceptor;
|
||||
import cn.axzo.framework.datapermission.context.DataPermissionContextFactory;
|
||||
import cn.axzo.framework.datapermission.rule.DataPermissionDefaultRule;
|
||||
import cn.axzo.framework.datapermission.rule.DataPermissionRule;
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.net.DatagramSocketImplFactory;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/31 16:34
|
||||
*/
|
||||
@ConditionalOnBean(MybatisPlusInterceptor.class)
|
||||
public class DataPermissionConfig {
|
||||
|
||||
@Bean
|
||||
public DataPermissionDefaultRule deptDataPermissionRule(FlowSupportApi permissionApi) {
|
||||
// 创建 DeptDataPermissionRule 对象
|
||||
return new DataPermissionDefaultRule(permissionApi);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(MybatisPlusInterceptor.class)
|
||||
public DataPermissionMybatisInterceptor mybatisDataPermissionInterceptor(MybatisPlusInterceptor mybatisPlusInterceptor, DataPermissionContextFactory dataPermissionContextFactory) {
|
||||
DataPermissionMybatisInterceptor dataPermissionMybatisInterceptor = new DataPermissionMybatisInterceptor(dataPermissionContextFactory);
|
||||
mybatisPlusInterceptor.addInnerInterceptor(dataPermissionMybatisInterceptor);
|
||||
return dataPermissionMybatisInterceptor;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public DataPermissionContextFactory dataPermissionRuleFactory(List<DataPermissionRule> rules) {
|
||||
return new DataPermissionContextFactory(rules);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package cn.axzo.framework.datapermission.context;
|
||||
|
||||
import cn.axzo.framework.datapermission.annotation.DataPermission;
|
||||
import cn.axzo.framework.datapermission.rule.DataPermissionRule;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/31 17:58
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class DataPermissionContextFactory {
|
||||
|
||||
List<DataPermissionRule> rules;
|
||||
|
||||
|
||||
public List<DataPermissionRule> getRules() {
|
||||
return rules;
|
||||
}
|
||||
|
||||
public List<DataPermissionRule> getRuleByDataPermission(DataPermission dataPermission) {
|
||||
Class<? extends DataPermissionRule>[] classes = dataPermission.includeRule();
|
||||
return rules.stream().filter(rule -> Arrays.stream(classes).anyMatch(e -> e.equals(rule.getClass()))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.framework.datapermission.context;
|
||||
|
||||
import cn.axzo.framework.datapermission.annotation.DataPermission;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据权限上下文
|
||||
*
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/31 11:42
|
||||
*/
|
||||
public class DataPermissionContextHolder {
|
||||
|
||||
private final static ThreadLocal<DataPermissionContext> DATA_PERMISSION_CONTEXT = new ThreadLocal<>();
|
||||
|
||||
|
||||
public static void setContext(DataPermissionContext dataPermission) {
|
||||
DATA_PERMISSION_CONTEXT.set(dataPermission);
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public static class DataPermissionContext {
|
||||
private DataPermission dataPermission;
|
||||
private Long ouId;
|
||||
private Long workspaceId;
|
||||
private Long personId;
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
DATA_PERMISSION_CONTEXT.remove();
|
||||
}
|
||||
|
||||
public static DataPermissionContext get() {
|
||||
return DATA_PERMISSION_CONTEXT.get();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,168 @@
|
||||
package cn.axzo.framework.datapermission.rule;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.NullValue;
|
||||
import net.sf.jsqlparser.expression.Parenthesis;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/30 18:35
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DataPermissionDefaultRule implements DataPermissionRule {
|
||||
static final Expression EXPRESSION_NULL = new NullValue();
|
||||
|
||||
private static final String DEFAULT_PERSON = "person_id";
|
||||
private static final String DEFAULT_NODE = "organizational_node_id";
|
||||
/**
|
||||
* key 表名
|
||||
* value 组织节点字段
|
||||
*/
|
||||
protected final Map<String, String> nodeTable = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* key 表名
|
||||
* value personId字段
|
||||
*/
|
||||
protected final Map<String, String> personTable = new ConcurrentHashMap<>();
|
||||
|
||||
protected final Set<String> tableName =new HashSet<>();
|
||||
|
||||
|
||||
//// TODO: 2024/6/3 查询数据权限的api
|
||||
private final FlowSupportApi permissionApi;
|
||||
|
||||
@Override
|
||||
public Set<String> getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getExpression(String tableName, Alias tableAlias) {
|
||||
|
||||
// TODO: 2024/5/31 可访问的数据 @李龙
|
||||
List<Long> nodeIds = ListUtil.of(1L, 2L, 3L);
|
||||
List<Long> personIds = ListUtil.of(110L, 223L);
|
||||
|
||||
Expression deptExpression = buildExpression(tableName, tableAlias, nodeIds);
|
||||
Expression userExpression = buildExpression(tableName, tableAlias, personIds);
|
||||
if (deptExpression == null && userExpression == null) {
|
||||
// 未获取到数据权限 返回NULL 不查询数据
|
||||
return EXPRESSION_NULL;
|
||||
}
|
||||
if (deptExpression == null) {
|
||||
return userExpression;
|
||||
}
|
||||
if (userExpression == null) {
|
||||
return deptExpression;
|
||||
}
|
||||
// 如果两个都有,用or WHERE (organizational_Node_id IN ? OR person_id in ?)
|
||||
return new Parenthesis(new OrExpression(deptExpression, userExpression));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*
|
||||
* @param tableName
|
||||
* @param tableAlias
|
||||
* @param ids 可能是nodeids 也可以是personIds
|
||||
* @return
|
||||
*/
|
||||
private Expression buildExpression(String tableName, Alias tableAlias, List<Long> ids) {
|
||||
// 如果不存在配置,则无需作为条件
|
||||
String columnName = nodeTable.get(tableName);
|
||||
if (!StringUtils.hasText(columnName)) {
|
||||
return null;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return null;
|
||||
}
|
||||
// 拼接条件
|
||||
return new InExpression(
|
||||
getColumn(tableAlias, columnName)
|
||||
, new ExpressionList(ids.stream().map(LongValue::new).collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
|
||||
private Column getColumn(Alias tableAlias, String columnName) {
|
||||
String result = tableAlias.getName() + StringPool.DOT +
|
||||
columnName;
|
||||
return new Column(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组织节点所对应的字段
|
||||
*
|
||||
* @param entityClass 表所对应的entity
|
||||
* @param columnName 字段名称 如:organizational_node_id
|
||||
*/
|
||||
public void addNodeColumn(Class<? extends Model<?>> entityClass, String columnName) {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
|
||||
if (null == tableInfo) {
|
||||
return;
|
||||
}
|
||||
nodeTable.put(tableInfo.getTableName(), columnName);
|
||||
tableName.add(tableInfo.getTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组织节点所对应的字段 字段默认使用organizational_node_id
|
||||
*
|
||||
* @param entityClass 表所对应的entity
|
||||
*/
|
||||
public void addNodeColumn(Class<? extends Model<?>> entityClass) {
|
||||
addNodeColumn(entityClass, DEFAULT_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加personId所对应的字段
|
||||
*
|
||||
* @param entityClass 表所对应的entity
|
||||
* @param columnName 字段名称 如:person_id
|
||||
*/
|
||||
public void addPersonColumn(Class<? extends Model<?>> entityClass, String columnName) {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
|
||||
if (null == tableInfo) {
|
||||
return;
|
||||
}
|
||||
personTable.put(tableInfo.getTableName(), columnName);
|
||||
tableName.add(tableInfo.getTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段默认使用person_id
|
||||
*
|
||||
* @param entityClass 表所对应的entity
|
||||
*/
|
||||
public void addPersonColumn(Class<? extends Model<?>> entityClass) {
|
||||
addPersonColumn(entityClass, DEFAULT_PERSON);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package cn.axzo.framework.datapermission.rule;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2024/5/30 18:31
|
||||
*/
|
||||
public interface DataPermissionRule {
|
||||
|
||||
Set<String> getTableName();
|
||||
|
||||
Expression getExpression(String tableName, Alias tableAlias);
|
||||
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.axzo.framework.datapermission.config.DataPermissionConfig
|
||||
Loading…
Reference in New Issue
Block a user