first commit
This commit is contained in:
@ -8,13 +8,13 @@ import com.qiaoba.auth.service.OnlineUserService;
|
|||||||
import com.qiaoba.auth.utils.TokenUtil;
|
import com.qiaoba.auth.utils.TokenUtil;
|
||||||
import com.qiaoba.common.redis.service.RedisService;
|
import com.qiaoba.common.redis.service.RedisService;
|
||||||
import com.qiaoba.common.web.utils.ResponseUtil;
|
import com.qiaoba.common.web.utils.ResponseUtil;
|
||||||
|
import com.qiaoba.common.web.utils.UriUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
import org.springframework.util.AntPathMatcher;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -40,7 +40,6 @@ public class AuthenticationCoreFilter extends OncePerRequestFilter {
|
|||||||
private final AuthConfigProperties authConfigProperties;
|
private final AuthConfigProperties authConfigProperties;
|
||||||
private final AuthConfigApiService authConfigApiService;
|
private final AuthConfigApiService authConfigApiService;
|
||||||
|
|
||||||
private final AntPathMatcher MATCH = new AntPathMatcher();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request,
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
@ -49,7 +48,7 @@ public class AuthenticationCoreFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
// 白名单 放行
|
// 白名单 放行
|
||||||
for (String uri : authConfigProperties.getWhitelist()) {
|
for (String uri : authConfigProperties.getWhitelist()) {
|
||||||
if (MATCH.match(uri,request.getRequestURI())) {
|
if (UriUtil.match(uri, request.getRequestURI())) {
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public class BaseContext {
|
|||||||
*
|
*
|
||||||
* @return Boolean
|
* @return Boolean
|
||||||
*/
|
*/
|
||||||
public static Boolean getSchema() {
|
public static Boolean isSchemaMode() {
|
||||||
return SCHEMA_HOLDER.get();
|
return SCHEMA_HOLDER.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ public class SchemaInterceptor implements InnerInterceptor {
|
|||||||
@Override
|
@Override
|
||||||
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
|
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
|
||||||
|
|
||||||
if (Objects.nonNull(BaseContext.getSchema()) && BaseContext.getSchema()) {
|
if (Objects.nonNull(BaseContext.isSchemaMode()) && BaseContext.isSchemaMode()) {
|
||||||
// use qiaoba-1;
|
// eg: use qiaoba-1;
|
||||||
String sql = StrUtil.format("use `{}-{}`;", baseDatabase, BaseContext.getTenantId());
|
String sql = StrUtil.format("use `{}-{}`;", baseDatabase, BaseContext.getTenantId());
|
||||||
try {
|
try {
|
||||||
conn.createStatement().execute(sql);
|
conn.createStatement().execute(sql);
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.qiaoba.common.web.utils;
|
||||||
|
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UriUtil
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023-06-11 12:01:18
|
||||||
|
*/
|
||||||
|
public class UriUtil {
|
||||||
|
|
||||||
|
private static final AntPathMatcher MATCH = new AntPathMatcher();
|
||||||
|
|
||||||
|
private UriUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通配符匹配
|
||||||
|
*
|
||||||
|
* @param pattern 通配符
|
||||||
|
* @param path uri
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static boolean match(String pattern, String path) {
|
||||||
|
return MATCH.match(pattern, path);
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import jakarta.validation.constraints.NotBlank;
|
|||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ import java.util.Date;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@TableName("sys_tenant")
|
@TableName("sys_tenant")
|
||||||
|
@NoArgsConstructor
|
||||||
public class SysTenant extends BaseEntity {
|
public class SysTenant extends BaseEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -85,4 +87,8 @@ public class SysTenant extends BaseEntity {
|
|||||||
|
|
||||||
private String mode;
|
private String mode;
|
||||||
|
|
||||||
|
public SysTenant(String tenantId, String status) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.qiaoba.module.tenant.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户状态
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023/6/5 16:33
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum TenantStatusEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用
|
||||||
|
*/
|
||||||
|
DISABLE("1", "禁用"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期
|
||||||
|
*/
|
||||||
|
EXPIRE("2", "过期");
|
||||||
|
|
||||||
|
|
||||||
|
private final String status;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
TenantStatusEnum(String code, String info) {
|
||||||
|
this.status = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
@ -2,14 +2,17 @@ package com.qiaoba.module.tenant.filters;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.qiaoba.auth.properties.AuthConfigProperties;
|
||||||
import com.qiaoba.common.base.constants.TenantConstant;
|
import com.qiaoba.common.base.constants.TenantConstant;
|
||||||
import com.qiaoba.common.base.context.BaseContext;
|
import com.qiaoba.common.base.context.BaseContext;
|
||||||
import com.qiaoba.common.base.enums.BaseEnum;
|
|
||||||
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
||||||
import com.qiaoba.common.database.constants.DynamicDatasourceConstant;
|
import com.qiaoba.common.database.constants.DynamicDatasourceConstant;
|
||||||
import com.qiaoba.common.web.utils.ResponseUtil;
|
import com.qiaoba.common.web.utils.ResponseUtil;
|
||||||
|
import com.qiaoba.common.web.utils.UriUtil;
|
||||||
import com.qiaoba.module.tenant.entity.SysTenant;
|
import com.qiaoba.module.tenant.entity.SysTenant;
|
||||||
|
import com.qiaoba.module.tenant.enums.TenantStatusEnum;
|
||||||
import com.qiaoba.module.tenant.service.SysTenantService;
|
import com.qiaoba.module.tenant.service.SysTenantService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
@ -32,35 +35,50 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Order(-10000)
|
@Order(-10000)
|
||||||
|
@Slf4j
|
||||||
public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SysTenantService sysTenantService;
|
private SysTenantService sysTenantService;
|
||||||
@Resource
|
@Resource
|
||||||
private DynamicDataSourceConfig dynamicDataSourceConfig;
|
private DynamicDataSourceConfig dynamicDataSourceConfig;
|
||||||
|
@Resource
|
||||||
|
private AuthConfigProperties authConfigProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT);
|
String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT);
|
||||||
// 主库或没有tenantId
|
// 主系统
|
||||||
if (StrUtil.isBlank(tenantId)
|
if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
|
||||||
|| TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)
|
|
||||||
|| request.getRequestURI().startsWith("/tenant")) {
|
|
||||||
dynamicDataSourceConfig.setDefaultSetting();
|
dynamicDataSourceConfig.setDefaultSetting();
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
|
after();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 白名单
|
||||||
|
for (String uri : authConfigProperties.getWhitelist()) {
|
||||||
|
if (UriUtil.match(uri, request.getRequestURI())) {
|
||||||
|
dynamicDataSourceConfig.setDefaultSetting();
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
after();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SysTenant sysTenant = sysTenantService.selectById(tenantId);
|
SysTenant sysTenant = sysTenantService.selectById(tenantId);
|
||||||
|
// 检查租户是否允许访问
|
||||||
if (checkTenantIsNotAllow(response, sysTenant)) {
|
if (checkTenantIsNotAllow(response, sysTenant)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 设置租户信息
|
||||||
before(sysTenant);
|
before(sysTenant);
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
after();
|
after();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void before(SysTenant sysTenant) {
|
private void before(SysTenant sysTenant) {
|
||||||
|
log.debug(StrUtil.format("设置租户信息, 租户ID: {},租户模式: {}", sysTenant.getTenantId(), sysTenant.getMode()));
|
||||||
BaseContext.setTenantId(sysTenant.getTenantId());
|
BaseContext.setTenantId(sysTenant.getTenantId());
|
||||||
BaseContext.setSchema(sysTenant.getMode().equals(SysTenant.SCHEMA_MODE));
|
BaseContext.setSchema(sysTenant.getMode().equals(SysTenant.SCHEMA_MODE));
|
||||||
// 数据源模式-设置第三方数据源
|
// 数据源模式-设置第三方数据源
|
||||||
@ -68,7 +86,7 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
//设置当前租户对应的数据源
|
//设置当前租户对应的数据源
|
||||||
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + sysTenant.getTenantId());
|
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + sysTenant.getTenantId());
|
||||||
}
|
}
|
||||||
// 字段模式/Schema模式-数据源选择默认数据源
|
// 字段模式 or Schema模式-数据源选择默认数据源
|
||||||
else {
|
else {
|
||||||
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID);
|
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID);
|
||||||
}
|
}
|
||||||
@ -77,6 +95,7 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void after() {
|
private void after() {
|
||||||
|
log.debug("clear the BaseContext");
|
||||||
BaseContext.clearAllHolder();
|
BaseContext.clearAllHolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,15 +112,22 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sysTenant.getStatus().equals(BaseEnum.ABNORMAL.getCode())) {
|
if (TenantStatusEnum.DISABLE.getStatus().equals(sysTenant.getStatus())) {
|
||||||
// 封禁状态
|
// 封禁状态
|
||||||
ResponseUtil.errorAuth(response, 401, "租户已被封禁");
|
ResponseUtil.errorAuth(response, 401, "租户已被封禁");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TenantStatusEnum.EXPIRE.getStatus().equals(sysTenant.getStatus())) {
|
||||||
|
// 已过期
|
||||||
|
ResponseUtil.errorAuth(response, 401, "租户已过期");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (DateUtil.compare(sysTenant.getExpireTime(), new Date()) < 0) {
|
if (DateUtil.compare(sysTenant.getExpireTime(), new Date()) < 0) {
|
||||||
// 已过期
|
// 已过期
|
||||||
ResponseUtil.errorAuth(response, 401, "租户已过期");
|
ResponseUtil.errorAuth(response, 401, "租户已过期");
|
||||||
|
// 更新租户状态为已过期
|
||||||
|
sysTenantService.update(new SysTenant(sysTenant.getTenantId(), TenantStatusEnum.EXPIRE.getStatus()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user