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