Browse Source

👣 重构底层多租户

master
wangxiang 3 years ago
parent
commit
5aa43c19e9
  1. 4
      kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/handler/KiccTenantLineHandler.java
  2. 70
      kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/override/TenantLikeExpression.java
  3. 78
      kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/plugins/KiccTenantLineInnerInterceptor.java
  4. 14
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/impl/UserServiceImpl.java

4
kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/handler/KiccTenantLineHandler.java

@ -3,9 +3,9 @@ package com.cloud.kicc.common.data.handler;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.cloud.kicc.common.data.entity.KiccUser; import com.cloud.kicc.common.data.entity.KiccUser;
import com.cloud.kicc.common.data.override.TenantLikeExpression;
import com.cloud.kicc.common.data.properties.TenantProperties; import com.cloud.kicc.common.data.properties.TenantProperties;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Column;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@ -57,7 +57,7 @@ public class KiccTenantLineHandler implements TenantLineHandler {
@Override @Override
public Expression getTenantId() { public Expression getTenantId() {
// 返回当前用户所属的多租户ID进行条件拼接 // 返回当前用户所属的多租户ID进行条件拼接
return ObjectUtil.isNotEmpty(getUser()) ? new StringValue(getUser().getTenantId()) : null; return ObjectUtil.isNotEmpty(getUser()) ? new TenantLikeExpression(getUser().getTenantId()) : null;
} }
/** /**

70
kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/override/TenantLikeExpression.java

@ -0,0 +1,70 @@
package com.cloud.kicc.common.data.override;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
import java.util.Objects;
/**
*<p>
* 重写StringValue,支持多租户like拼接查询
* 由于内部StringExpression会拼接默认会加''
* 而多租户like条件经过处理不许需要加'',如果加上会导致数据查不出
*</p>
*
* @Author: entfrm开发团队-王翔
* @Date: 2022/5/11
*/
public class TenantLikeExpression extends ASTNodeAccessImpl implements Expression {
private String value = "";
public TenantLikeExpression() {
}
public TenantLikeExpression(String escapedValue) {
this.value = escapedValue;
}
public String getValue() {
return this.value;
}
public void setValue(String string) {
this.value = string;
}
@Override
public void accept(ExpressionVisitor expressionVisitor) {
}
@Override
public String toString() {
return this.value;
}
public TenantLikeExpression withValue(String value) {
this.setValue(value);
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
TenantLikeExpression that = (TenantLikeExpression)o;
return Objects.equals(this.value, that.value);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(new Object[]{this.value});
}
}

78
kicc-common/kicc-common-data/src/main/java/com/cloud/kicc/common/data/plugins/KiccTenantLineInnerInterceptor.java

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.cloud.kicc.common.data.override.TenantLikeExpression;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis; import net.sf.jsqlparser.expression.Parenthesis;
@ -13,8 +14,8 @@ import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression; import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList; import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList; import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.schema.Table;
@ -37,7 +38,7 @@ import java.util.stream.Collectors;
/** /**
*<p> *<p>
* 租户线路内部拦截器 * 租户线路内部拦截器
* 重构租户线路内部拦截器,支持查询多个多租户ID,默认只支持一个多租户id查询 * 重构租户线路内部拦截器,支持查询多个多租户ID,还支持查询多个租户的共享数据,默认只支持一个多租户id查询
* 支持多租户ID不存在时,查询所有租户ID数据 * 支持多租户ID不存在时,查询所有租户ID数据
*</p> *</p>
* *
@ -76,12 +77,21 @@ public class KiccTenantLineInnerInterceptor extends TenantLineInnerInterceptor {
String tenantIdColumn = this.tenantLineHandler.getTenantIdColumn(); String tenantIdColumn = this.tenantLineHandler.getTenantIdColumn();
if (!this.tenantLineHandler.ignoreInsert(columns, tenantIdColumn)) { if (!this.tenantLineHandler.ignoreInsert(columns, tenantIdColumn)) {
columns.add(new Column(tenantIdColumn)); columns.add(new Column(tenantIdColumn));
List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList(); List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList();
if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) { if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
// 替换InExpression支持查询多个租户ID的条件 // 替换likeExpression支持查询多个租户ID的条件,包括查询数据对应多个多租户ID的数据
InExpression inExpression = new InExpression(); List<String> tenantIds = StrUtil.split(this.tenantLineHandler.getTenantId().toString(), ",");
inExpression.setLeftExpression(new StringValue(tenantIdColumn)); StringBuilder statementBuilder = new StringBuilder();
inExpression.setRightItemsList(new ExpressionList(this.tenantLineHandler.getTenantId())); tenantIds.forEach(tenantId -> {
LikeExpression likeExpression = new LikeExpression();
likeExpression.setLeftExpression(new Column(tenantIdColumn));
likeExpression.setRightExpression(new StringValue("%" + tenantId + "%"));
statementBuilder.append(likeExpression + " OR ");
});
statementBuilder.delete(statementBuilder.length()-4, statementBuilder.length());
TenantLikeExpression tenantLikeExpression = new TenantLikeExpression(statementBuilder.toString());
duplicateUpdateColumns.add(tenantLikeExpression);
} }
Select select = insert.getSelect(); Select select = insert.getSelect();
@ -111,27 +121,34 @@ public class KiccTenantLineInnerInterceptor extends TenantLineInnerInterceptor {
protected void processUpdate(Update update, int index, String sql, Object obj) { protected void processUpdate(Update update, int index, String sql, Object obj) {
Table table = update.getTable(); Table table = update.getTable();
if (!this.tenantLineHandler.ignoreTable(table.getName())) { if (!this.tenantLineHandler.ignoreTable(table.getName())) {
update.setWhere(this.andInExpression(table, update.getWhere())); update.setWhere(this.andLikeExpression(table, update.getWhere()));
} }
} }
@Override @Override
protected void processDelete(Delete delete, int index, String sql, Object obj) { protected void processDelete(Delete delete, int index, String sql, Object obj) {
if (!this.tenantLineHandler.ignoreTable(delete.getTable().getName())) { if (!this.tenantLineHandler.ignoreTable(delete.getTable().getName())) {
delete.setWhere(this.andInExpression(delete.getTable(), delete.getWhere())); delete.setWhere(this.andLikeExpression(delete.getTable(), delete.getWhere()));
} }
} }
/** 重写andExpression表达式,支持in查询多个参数 */ /** 重写andExpression表达式,支持like查询多个参数 */
protected Expression andInExpression(Table table, Expression where) { protected Expression andLikeExpression(Table table, Expression where) {
// 替换InExpression支持查询多个租户ID的条件 // 替换likeExpression支持查询多个租户ID的条件,包括查询数据对应多个多租户ID的数据
InExpression inExpression = new InExpression(); List<String> tenantIds = StrUtil.split(this.tenantLineHandler.getTenantId().toString(), ",");
inExpression.setLeftExpression(this.getAliasColumn(table)); StringBuilder statementBuilder = new StringBuilder();
inExpression.setRightItemsList(new ExpressionList(this.tenantLineHandler.getTenantId())); tenantIds.forEach(tenantId -> {
LikeExpression likeExpression = new LikeExpression();
likeExpression.setLeftExpression(this.getAliasColumn(table));
likeExpression.setRightExpression(new StringValue("%" + tenantId + "%"));
statementBuilder.append(likeExpression + " OR ");
});
statementBuilder.delete(statementBuilder.length()-4, statementBuilder.length());
TenantLikeExpression tenantLikeExpression = new TenantLikeExpression(statementBuilder.toString());
if (null != where) { if (null != where) {
return where instanceof OrExpression ? new AndExpression(inExpression, new Parenthesis(where)) : new AndExpression(inExpression, where); return where instanceof OrExpression ? new AndExpression(tenantLikeExpression, new Parenthesis(where)) : new AndExpression(tenantLikeExpression, where);
} else { } else {
return inExpression; return tenantLikeExpression;
} }
} }
@ -140,18 +157,29 @@ public class KiccTenantLineInnerInterceptor extends TenantLineInnerInterceptor {
if (CollectionUtils.isEmpty(tables)) { if (CollectionUtils.isEmpty(tables)) {
return currentExpression; return currentExpression;
} else { } else {
Expression tenantId = this.tenantLineHandler.getTenantId(); // 替换likeExpression支持查询多个租户ID的条件,包括查询数据对应多个多租户ID的数据
// 替换InExpression支持查询多个租户ID的条件 List<TenantLikeExpression> strExpressions = tables.stream()
List<InExpression> inExpressions = tables.stream()
.filter(x -> !this.tenantLineHandler.ignoreTable(x.getName())) .filter(x -> !this.tenantLineHandler.ignoreTable(x.getName()))
.map(item -> new InExpression(this.getAliasColumn(item), new ExpressionList(tenantId))).collect(Collectors.toList()); .map(item -> {
if (CollectionUtils.isEmpty(inExpressions)) { List<String> tenantIds = StrUtil.split(this.tenantLineHandler.getTenantId().toString(), ",");
StringBuilder statementBuilder = new StringBuilder();
tenantIds.forEach(tenantId -> {
LikeExpression likeExpression = new LikeExpression();
likeExpression.setLeftExpression(this.getAliasColumn(item));
likeExpression.setRightExpression(new StringValue("%" + tenantId + "%"));
statementBuilder.append(likeExpression + " OR ");
});
statementBuilder.delete(statementBuilder.length()-4, statementBuilder.length());
TenantLikeExpression tenantLikeExpression = new TenantLikeExpression(statementBuilder.toString());
return tenantLikeExpression;
}).collect(Collectors.toList());
if (CollectionUtils.isEmpty(strExpressions)) {
return currentExpression; return currentExpression;
} else { } else {
Expression injectExpression = inExpressions.get(0); Expression injectExpression = strExpressions.get(0);
if (inExpressions.size() > 1) { if (strExpressions.size() > 1) {
for(int i = 1; i < inExpressions.size(); ++i) { for(int i = 1; i < strExpressions.size(); ++i) {
injectExpression = new AndExpression(injectExpression, inExpressions.get(i)); injectExpression = new AndExpression(injectExpression, strExpressions.get(i));
} }
} }

14
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/impl/UserServiceImpl.java

@ -5,19 +5,21 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloud.kicc.common.core.constant.SecurityConstants;
import com.cloud.kicc.common.core.exception.CheckedException;
import com.cloud.kicc.system.api.entity.Dept; import com.cloud.kicc.system.api.entity.Dept;
import com.cloud.kicc.system.api.entity.Role; import com.cloud.kicc.system.api.entity.Role;
import com.cloud.kicc.system.api.entity.User; import com.cloud.kicc.system.api.entity.User;
import com.cloud.kicc.system.api.entity.UserRole; import com.cloud.kicc.system.api.entity.UserRole;
import com.cloud.kicc.system.mapper.UserMapper; import com.cloud.kicc.system.mapper.UserMapper;
import com.cloud.kicc.system.service.*; import com.cloud.kicc.system.service.*;
import com.cloud.kicc.common.core.constant.SecurityConstants;
import com.cloud.kicc.common.core.exception.CheckedException;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ServerErrorException;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -63,7 +65,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
} }
} }
@Override @Override
@SneakyThrows
public User getUserAuthority(User user) { public User getUserAuthority(User user) {
// 设置角色列表 // 设置角色列表
List<Role> roleList = roleService.selectMyRolesByUserId(user.getId()); List<Role> roleList = roleService.selectMyRolesByUserId(user.getId());
@ -89,8 +93,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
tenantCode.addAll(codes); tenantCode.addAll(codes);
}); });
// 检测多租户信息是否存在,不存在抛出异常 // 检测多租户信息是否存在,不存在抛出异常
if (tenantCode.size() == 0) {
throw new Exception("当前用户多租户不存在,请联系统管理员检查多租户是否过期或者冻结!");
}
user.setTenantId(String.join(",", tenantCode));
user.setPermissions(ArrayUtil.toArray(permissions, String.class)); user.setPermissions(ArrayUtil.toArray(permissions, String.class));
return user; return user;
} }

Loading…
Cancel
Save