需求默认租户下的角色需要看到全部数据,直接上代码
实现TenantLineHandler接口重写方法
package org.springblade.common.config;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.BladeTenantHolder;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author: chenl
* @Date: 2024/7/24
*/
public class MyTenantLineHandler implements TenantLineHandler {
/**
* 需要排除进行自定义的多租户表
*/
private final List<String> excludeTableList = Arrays.asList("blade_user", "blade_dept", "blade_role", "blade_tenant", "act_de_model");
/**
* 匹配的多租户表
*/
private final Set<String> tenantTableList = new HashSet<>();
@Override
public Expression getTenantId() {
// 另一种写法,可以实现模糊查询多个租户,但是我这里不需要
// LikeExpression likeExpression = new LikeExpression();
// likeExpression.withRightExpression(new StringValue("%" + "000000" + "%"));
// return likeExpression;
// 坑:AuthUtil.getTenantId()在登录是是空字符串,Func.toStr无法识别
String tenantId = Func.toStr(AuthUtil.getTenantId().isEmpty() ?null:AuthUtil.getTenantId(), BladeConstant.ADMIN_TENANT_ID);;
return new StringValue(tenantId);
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
/**
* 根据表名判断是否忽略拼接多租户条件
* 默认都要进行解析并拼接多租户条件
*
* @param tableName 表名
* @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件
*/
@Override
public boolean ignoreTable(String tableName) {
if (BladeTenantHolder.isIgnore()) {
return true;
}
// 添加需要排除的表,表里没有租户id的,更加具体环境,BladeConstant.ADMIN_TENANT_ID就是枚举默认值000000
tenantTableList.add("blade_dict");
tenantTableList.add("blade_menu");
tenantTableList.add("blade_role_menu");
tenantTableList.add("blade_tenant_package");
tenantTableList.add("blade_user_web");
String tenantId = Func.toStr(AuthUtil.getTenantId().isEmpty() ?null:AuthUtil.getTenantId(), BladeConstant.ADMIN_TENANT_ID);
boolean result = tenantTableList.contains(tableName) && StringUtil.isNotBlank(tenantId);
return result;
}
}
继承TenantLineInnerInterceptor重写如下方法
package org.springblade.common.config;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.schema.Table;
import org.springblade.core.secure.utils.AuthUtil;
import java.util.Arrays;
import java.util.List;
/**
* @Author: chenl
* @Date: 2024/7/24
*/
public class MyTenantLineInnerInterceptor extends TenantLineInnerInterceptor {
private MyTenantLineHandler tenantLineHandler;
/**
* 超管需要启用租户过滤的表
*/
private List<String> adminTenantTables = Arrays.asList("blade_top_menu", "blade_dict_biz");
public TenantLineHandler getTenantLineHandler() {
return this.tenantLineHandler;
}
public void setTenantLineHandler(final MyTenantLineHandler tenantLineHandler) {
this.tenantLineHandler = tenantLineHandler;
}
public MyTenantLineInnerInterceptor() {
}
public MyTenantLineInnerInterceptor(final MyTenantLineHandler tenantLineHandler) {
super.setTenantLineHandler(tenantLineHandler);
this.tenantLineHandler = tenantLineHandler;
}
@Override
public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
//若是忽略的表则不进行数据隔离
if (this.tenantLineHandler.ignoreTable(table.getName())) {
return null;
}
//若是超管则不进行数据隔离
if (doTenantFilter(table.getName())) {
return null;
}
// 默认租户可以查看所有数据(自定义,上面两个是bladex原逻辑)
if(ObjectUtil.contains(this.tenantLineHandler.getTenantId().toString(),"000000")){
return null;
}
//获得条件表达式
return new EqualsTo(getAliasColumn(table), this.tenantLineHandler.getTenantId());
// 模糊查询使用的逻辑,我不需要
// if (this.tenantLineHandler.ignoreTable(table.getName())) {
// return null;
// }
// Expression expression = this.tenantLineHandler.getTenantId();
// LikeExpression likeExpression = null;
// if (expression instanceof LikeExpression) {
// likeExpression = (LikeExpression) expression;
// likeExpression.withLeftExpression(this.getAliasColumn(table));
// }
// return likeExpression;
}
// protected Column getAliasColumn(Table table) {
// StringBuilder column = new StringBuilder();
// if (table.getAlias() != null) {
// column.append(table.getAlias().getName()).append(".");
// }
//
// column.append(this.tenantLineHandler.getTenantIdColumn());
// return new Column(column.toString());
// }
/**
* 判断当前操作是否需要进行过滤
*
* @param tableName 表名
*/
public boolean doTenantFilter(String tableName) {
return AuthUtil.isAdministrator() && !adminTenantTables.contains(tableName);
}
/**
* 判断当前操作是否需要进行过滤
*
* @param tables 表名
*/
// public boolean doTenantFilters(List<Table> tables) {
// List<String> tableNames = tables.stream().map(Table::getName).collect(Collectors.toList());
// return AuthUtil.isAdministrator() && !CollectionUtil.containsAny(adminTenantTables, tableNames);
// }
}
再配置类里添加自定义的注入,任意配置类
/**
* 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.common.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.oauth2.endpoint.OAuth2SocialEndpoint;
import org.springblade.core.oauth2.endpoint.OAuth2TokenEndPoint;
import org.springblade.core.secure.registry.SecureRegistry;
import org.springblade.core.tool.utils.StringPool;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Blade配置
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
public class BladeConfiguration implements WebMvcConfigurer {
/**
* 安全框架配置
*/
@Bean
public SecureRegistry secureRegistry() {
SecureRegistry secureRegistry = new SecureRegistry();
secureRegistry.setEnabled(true);
secureRegistry.excludePathPatterns("/blade-auth/**");
secureRegistry.excludePathPatterns("/blade-system/tenant/info");
secureRegistry.excludePathPatterns("/blade-system/tenant/list");
secureRegistry.excludePathPatterns("/blade-system/tenant/register");
secureRegistry.excludePathPatterns("/blade-system/tenant/checkCaptchaTenant");
secureRegistry.excludePathPatterns("/blade-flow/process/resource-view");
secureRegistry.excludePathPatterns("/blade-flow/process/diagram-view");
secureRegistry.excludePathPatterns("/blade-flow/manager/check-upload");
secureRegistry.excludePathPatterns("/doc.html");
secureRegistry.excludePathPatterns("/swagger-ui.html");
secureRegistry.excludePathPatterns("/static/**");
secureRegistry.excludePathPatterns("/webjars/**");
secureRegistry.excludePathPatterns("/swagger-resources/**");
secureRegistry.excludePathPatterns("/druid/**");
secureRegistry.excludePathPatterns("/blade-system/region/**");
return secureRegistry;
}
/**
* 跨域配置
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/cors/**")
.allowedOriginPatterns("*")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(3600)
.allowCredentials(true);
}
/**
* 给OAuth2服务端添加前缀
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix(StringPool.SLASH + AppConstant.APPLICATION_AUTH_NAME,
c -> c.isAnnotationPresent(RestController.class) && (
OAuth2TokenEndPoint.class.equals(c) || OAuth2SocialEndpoint.class.equals(c))
);
}
// 主要这个,注入我们自定义的bean
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 保留分页插件,不然无法分页
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new MyTenantLineInnerInterceptor(new MyTenantLineHandler()));
return interceptor;
}
}
结束,参考文章:添加链接描述