mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 09:11:52 +08:00
1. 增加 Job 的多租户的能力
This commit is contained in:
parent
535d3c9c01
commit
6cd9b3bf7e
@ -2,6 +2,7 @@ package cn.iocoder.yudao.adminserver.modules.system.job.auth;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
|
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ import javax.annotation.Resource;
|
|||||||
* @author 願
|
* @author 願
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
|
@TenantJob
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SysUserSessionTimeoutJob implements JobHandler {
|
public class SysUserSessionTimeoutJob implements JobHandler {
|
||||||
|
|
||||||
|
@ -74,6 +74,6 @@ yudao:
|
|||||||
- cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants
|
- cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants
|
||||||
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
|
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
|
||||||
tenant:
|
tenant:
|
||||||
tables: sys_user
|
tables: sys_user, sys_user_session
|
||||||
|
|
||||||
debug: false
|
debug: false
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
|
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -25,7 +25,7 @@ import java.util.Date;
|
|||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SysUserSessionDO extends BaseDO {
|
public class SysUserSessionDO extends TenantBaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 会话编号, 即 sessionId
|
* 会话编号, 即 sessionId
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName(value = "sys_tenant", autoResultMap = true)
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class SysTenantDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户编号,自增
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 租户名,唯一
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* 联系人
|
||||||
|
*/
|
||||||
|
private String contactName;
|
||||||
|
/**
|
||||||
|
* 联系手机
|
||||||
|
*/
|
||||||
|
private String contactMobile;
|
||||||
|
/**
|
||||||
|
* 帐号状态
|
||||||
|
*
|
||||||
|
* 枚举 {@link CommonStatusEnum}
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SysTenantCoreMapper extends BaseMapperX<SysTenantDO> {
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package cn.iocoder.yudao.coreservice.modules.system.service.tenant;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface SysTenantCoreService extends TenantFrameworkService {
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.coreservice.modules.system.service.tenant.impl;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant.SysTenantCoreMapper;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.system.service.tenant.SysTenantCoreService;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SysTenantCoreServiceImpl implements SysTenantCoreService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysTenantCoreMapper tenantCoreMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> getTenantIds() {
|
||||||
|
List<SysTenantDO> tenants = tenantCoreMapper.selectList();
|
||||||
|
return CollectionUtils.convertList(tenants, SysTenantDO::getId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
package cn.iocoder.yudao.framework.security.config;
|
package cn.iocoder.yudao.framework.security.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
|
import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy;
|
||||||
import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
|
import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
|
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
|
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;
|
import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;
|
||||||
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
|
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
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.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
@ -85,4 +88,17 @@ public class YudaoSecurityAutoConfiguration {
|
|||||||
return new JWTAuthenticationTokenFilter(securityProperties, securityFrameworkService, globalExceptionHandler);
|
return new JWTAuthenticationTokenFilter(securityProperties, securityFrameworkService, globalExceptionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 声明调用 {@link SecurityContextHolder#setStrategyName(String)} 方法,
|
||||||
|
* 设置使用 {@link TransmittableThreadLocalSecurityContextHolderStrategy} 作为 Security 的上下文策略
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MethodInvokingFactoryBean securityContextHolderMethodInvokingFactoryBean() {
|
||||||
|
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
|
||||||
|
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
|
||||||
|
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
|
||||||
|
methodInvokingFactoryBean.setArguments(TransmittableThreadLocalSecurityContextHolderStrategy.class.getName());
|
||||||
|
return methodInvokingFactoryBean;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package cn.iocoder.yudao.framework.security.core.context;
|
||||||
|
|
||||||
|
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于 TransmittableThreadLocal 实现的 Security Context 持有者策略
|
||||||
|
* 目的是,避免 @Async 等异步执行时,原生 ThreadLocal 的丢失问题
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class TransmittableThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 TransmittableThreadLocal 作为上下文
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<SecurityContext> contextHolder = new TransmittableThreadLocal<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearContext() {
|
||||||
|
contextHolder.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityContext getContext() {
|
||||||
|
SecurityContext ctx = contextHolder.get();
|
||||||
|
if (ctx == null) {
|
||||||
|
ctx = createEmptyContext();
|
||||||
|
contextHolder.set(ctx);
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContext(SecurityContext context) {
|
||||||
|
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
|
||||||
|
contextHolder.set(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityContext createEmptyContext() {
|
||||||
|
return new SecurityContextImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -95,13 +95,14 @@ public class SecurityFrameworkUtils {
|
|||||||
loginUser, null, loginUser.getAuthorities());
|
loginUser, null, loginUser.getAuthorities());
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
// 设置到上下文
|
// 设置到上下文
|
||||||
//何时调用 SecurityContextHolder.clearContext. spring security filter 应该会调用 clearContext
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||||
// 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号;
|
// 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号;
|
||||||
// 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息
|
// 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息
|
||||||
WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
|
WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
|
||||||
WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
|
WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
|
||||||
// TODO @jason:使用 userId 会不会更合适哈?
|
// TODO @jason:使用 userId 会不会更合适哈?
|
||||||
|
// TODO @芋艿:activiti 需要使用 ttl 上下文
|
||||||
|
// TODO @jason:清理问题
|
||||||
if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) {
|
if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) {
|
||||||
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
|
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,12 @@
|
|||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Job 定时任务相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-job</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.framework.tenant.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户针对 Job 的自动配置
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class YudaoTenantJobAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
|
||||||
|
public BeanPostProcessor jobHandlerBeanPostProcessor(TenantFrameworkService tenantFrameworkService) {
|
||||||
|
return new BeanPostProcessor() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (!(bean instanceof JobHandler)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
// 有 TenantJob 注解的情况下,才会进行处理
|
||||||
|
if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 TenantJobHandlerDecorator 装饰
|
||||||
|
return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package cn.iocoder.yudao.framework.tenant.core.job;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户 Job 注解
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TenantJob {
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.yudao.framework.tenant.core.job;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户 JobHandler 装饰器
|
||||||
|
* 任务执行时,会按照租户逐个执行 Job 的逻辑
|
||||||
|
*
|
||||||
|
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class TenantJobHandlerDecorator implements JobHandler {
|
||||||
|
|
||||||
|
private final TenantFrameworkService tenantFrameworkService;
|
||||||
|
/**
|
||||||
|
* 被装饰的 Job
|
||||||
|
*/
|
||||||
|
private final JobHandler jobHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String execute(String param) throws Exception {
|
||||||
|
// 获得租户列表
|
||||||
|
List<Long> tenantIds = tenantFrameworkService.getTenantIds();
|
||||||
|
if (CollUtil.isEmpty(tenantIds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逐个租户,执行 Job
|
||||||
|
Map<Long, String> results = new ConcurrentHashMap<>();
|
||||||
|
tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
|
||||||
|
try {
|
||||||
|
// 设置租户
|
||||||
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
|
// 执行 Job
|
||||||
|
String result = jobHandler.execute(param);
|
||||||
|
// 添加结果
|
||||||
|
results.put(tenantId, result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
TenantContextHolder.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return JsonUtils.toJsonString(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package cn.iocoder.yudao.framework.tenant.core.job;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户 JobHandlerInvoker 拓展实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class TenantJobHandlerInvoker extends JobHandlerInvoker {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.framework.tenant.core.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tenant 框架 Service 接口,定义获取租户信息
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface TenantFrameworkService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得所有租户
|
||||||
|
*
|
||||||
|
* @return 租户编号数组
|
||||||
|
*/
|
||||||
|
List<Long> getTenantIds();
|
||||||
|
|
||||||
|
}
|
@ -12,7 +12,10 @@ import java.io.IOException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 多租户 Web 过滤器
|
* 多租户 Web 过滤器
|
||||||
* 将请求 Header 中的 tenant-id 解析出来,添加到 {@link TenantContextHolder} 中,这样后续的 DB 等操作,可以获得到租户编号
|
* 将请求 Header 中的 tenant-id 解析出来,添加到 {@link TenantContextHolder} 中,这样后续的 DB 等操作,可以获得到租户编号。
|
||||||
|
*
|
||||||
|
* Q:会不会存在模拟 tenant-id 导致跨租户的问题?
|
||||||
|
* A:用户登陆后,获得的 Token 是基于租户级别隔离,从而保证授权失败。
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* 多租户,支持如下层面:
|
* 多租户,支持如下层面:
|
||||||
* 1. DB:基于 MyBatis Plus 多租户的功能实现
|
* 1. DB:基于 MyBatis Plus 多租户的功能实现。
|
||||||
* 2. Job:TODO
|
* 2. Web:请求 HTTP API 时,Header 带上 tenant-id 租户编号。
|
||||||
* 3. MQ:TODO
|
* 3. Job:在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。
|
||||||
* 4. Web:TODO
|
* 4. MQ:TODO
|
||||||
*/
|
*/
|
||||||
package cn.iocoder.yudao.framework.tenant;
|
package cn.iocoder.yudao.framework.tenant;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.iocoder.yudao.framework.tenant.config.YudaoTenantDatabaseAutoConfiguration,\
|
cn.iocoder.yudao.framework.tenant.config.YudaoTenantDatabaseAutoConfiguration,\
|
||||||
cn.iocoder.yudao.framework.tenant.config.YudaoTenantWebAutoConfiguration
|
cn.iocoder.yudao.framework.tenant.config.YudaoTenantWebAutoConfiguration,\
|
||||||
|
cn.iocoder.yudao.framework.tenant.config.YudaoTenantJobAutoConfiguration
|
||||||
|
Loading…
Reference in New Issue
Block a user