Commit 79311ecc71f0c6beabe0e5f84e1423ce745a5f09

Authored by YunaiV
1 parent 27c30279

* 【新增】后端 `yudao.tenant.enable` 配置项,前端 `VUE_APP_TENANT_ENABLE` 配置项,用于开关租户功能

* 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略
* 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API
Showing 36 changed files with 220 additions and 122 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.common.enums; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.common.enums;
3 /** 3 /**
4 * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期 4 * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
5 * 5 *
6 - * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下 6 + * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
7 * 7 *
8 * @author 芋道源码 8 * @author 芋道源码
9 */ 9 */
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java
@@ -14,22 +14,28 @@ import java.util.Set; @@ -14,22 +14,28 @@ import java.util.Set;
14 @Data 14 @Data
15 public class TenantProperties { 15 public class TenantProperties {
16 16
17 -// /**  
18 -// * 租户是否开启  
19 -// */  
20 -// private static final Boolean ENABLE_DEFAULT = true;  
21 -//  
22 -// /**  
23 -// * 是否开启  
24 -// */  
25 -// private Boolean enable = ENABLE_DEFAULT; 17 + /**
  18 + * 租户是否开启
  19 + */
  20 + private static final Boolean ENABLE_DEFAULT = true;
  21 +
  22 + /**
  23 + * 是否开启
  24 + */
  25 + private Boolean enable = ENABLE_DEFAULT;
  26 +
  27 + /**
  28 + * 需要忽略多租户的请求
  29 + *
  30 + * 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!
  31 + */
  32 + private Set<String> ignoreUrls;
26 33
27 /** 34 /**
28 - * 需要多租户的表 35 + * 需要忽略多租户的表
29 * 36 *
30 - * 由于多租户并不作为 yudao 项目的重点功能,更多是扩展性的功能,所以采用正向配置需要多租户的表。  
31 - * 如果需要,你可以改成 ignoreTables 来取消部分不需要的表 37 + * 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
32 */ 38 */
33 - private Set<String> tables; 39 + private Set<String> ignoreTables;
34 40
35 } 41 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantDatabaseAutoConfiguration.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
4 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; 4 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
5 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
6 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; 6 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 import org.springframework.boot.context.properties.EnableConfigurationProperties;
8 import org.springframework.context.annotation.Bean; 9 import org.springframework.context.annotation.Bean;
9 import org.springframework.context.annotation.Configuration; 10 import org.springframework.context.annotation.Configuration;
@@ -14,6 +15,8 @@ import org.springframework.context.annotation.Configuration; @@ -14,6 +15,8 @@ import org.springframework.context.annotation.Configuration;
14 * @author 芋道源码 15 * @author 芋道源码
15 */ 16 */
16 @Configuration 17 @Configuration
  18 +// 允许使用 yudao.tenant.enable=false 禁用多租户
  19 +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
17 @EnableConfigurationProperties(TenantProperties.class) 20 @EnableConfigurationProperties(TenantProperties.class)
18 public class YudaoTenantDatabaseAutoConfiguration { 21 public class YudaoTenantDatabaseAutoConfiguration {
19 22
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantJobAutoConfiguration.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator;
7 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; 7 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
8 import org.springframework.beans.BeansException; 8 import org.springframework.beans.BeansException;
9 import org.springframework.beans.factory.config.BeanPostProcessor; 9 import org.springframework.beans.factory.config.BeanPostProcessor;
  10 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10 import org.springframework.context.annotation.Bean; 11 import org.springframework.context.annotation.Bean;
11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.context.annotation.Configuration;
12 13
@@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration; @@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration;
16 * @author 芋道源码 17 * @author 芋道源码
17 */ 18 */
18 @Configuration 19 @Configuration
  20 +// 允许使用 yudao.tenant.enable=false 禁用多租户
  21 +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
19 public class YudaoTenantJobAutoConfiguration { 22 public class YudaoTenantJobAutoConfiguration {
20 23
21 @Bean 24 @Bean
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantMQAutoConfiguration.java
1 package cn.iocoder.yudao.framework.tenant.config; 1 package cn.iocoder.yudao.framework.tenant.config;
2 2
3 import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; 3 import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor;
  4 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Bean;
5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.context.annotation.Configuration;
6 7
@@ -10,6 +11,8 @@ import org.springframework.context.annotation.Configuration; @@ -10,6 +11,8 @@ import org.springframework.context.annotation.Configuration;
10 * @author 芋道源码 11 * @author 芋道源码
11 */ 12 */
12 @Configuration 13 @Configuration
  14 +// 允许使用 yudao.tenant.enable=false 禁用多租户
  15 +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
13 public class YudaoTenantMQAutoConfiguration { 16 public class YudaoTenantMQAutoConfiguration {
14 17
15 @Bean 18 @Bean
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantSecurityAutoConfiguration.java
@@ -2,6 +2,9 @@ package cn.iocoder.yudao.framework.tenant.config; @@ -2,6 +2,9 @@ package cn.iocoder.yudao.framework.tenant.config;
2 2
3 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; 3 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
4 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; 4 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
  5 +import cn.iocoder.yudao.framework.web.config.WebProperties;
  6 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  7 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
5 import org.springframework.boot.web.servlet.FilterRegistrationBean; 8 import org.springframework.boot.web.servlet.FilterRegistrationBean;
6 import org.springframework.context.annotation.Bean; 9 import org.springframework.context.annotation.Bean;
7 import org.springframework.context.annotation.Configuration; 10 import org.springframework.context.annotation.Configuration;
@@ -12,12 +15,16 @@ import org.springframework.context.annotation.Configuration; @@ -12,12 +15,16 @@ import org.springframework.context.annotation.Configuration;
12 * @author 芋道源码 15 * @author 芋道源码
13 */ 16 */
14 @Configuration 17 @Configuration
  18 +// 允许使用 yudao.tenant.enable=false 禁用多租户
  19 +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
  20 +@EnableConfigurationProperties(TenantProperties.class)
15 public class YudaoTenantSecurityAutoConfiguration { 21 public class YudaoTenantSecurityAutoConfiguration {
16 22
17 @Bean 23 @Bean
18 - public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter() { 24 + public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter(TenantProperties tenantProperties,
  25 + WebProperties webProperties) {
19 FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>(); 26 FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>();
20 - registrationBean.setFilter(new TenantSecurityWebFilter()); 27 + registrationBean.setFilter(new TenantSecurityWebFilter(tenantProperties, webProperties));
21 registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER); 28 registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER);
22 return registrationBean; 29 return registrationBean;
23 } 30 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantWebAutoConfiguration.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.tenant.config; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.tenant.config;
2 2
3 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; 3 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
4 import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter; 4 import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter;
  5 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5 import org.springframework.boot.web.servlet.FilterRegistrationBean; 6 import org.springframework.boot.web.servlet.FilterRegistrationBean;
6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Bean;
7 import org.springframework.context.annotation.Configuration; 8 import org.springframework.context.annotation.Configuration;
@@ -12,6 +13,8 @@ import org.springframework.context.annotation.Configuration; @@ -12,6 +13,8 @@ import org.springframework.context.annotation.Configuration;
12 * @author 芋道源码 13 * @author 芋道源码
13 */ 14 */
14 @Configuration 15 @Configuration
  16 +// 允许使用 yudao.tenant.enable=false 禁用多租户
  17 +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
15 public class YudaoTenantWebAutoConfiguration { 18 public class YudaoTenantWebAutoConfiguration {
16 19
17 @Bean 20 @Bean
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java
@@ -33,7 +33,7 @@ public class TenantContextHolder { @@ -33,7 +33,7 @@ public class TenantContextHolder {
33 public static Long getRequiredTenantId() { 33 public static Long getRequiredTenantId() {
34 Long tenantId = getTenantId(); 34 Long tenantId = getTenantId();
35 if (tenantId == null) { 35 if (tenantId == null) {
36 - throw new NullPointerException("TenantContextHolder 不存在租户编号"); 36 + throw new NullPointerException("TenantContextHolder 不存在租户编号"); // TODO 芋艿:增加文档链接
37 } 37 }
38 return tenantId; 38 return tenantId;
39 } 39 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.tenant.core.db; @@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.tenant.core.db;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.tenant.config.TenantProperties; 4 import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
5 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 5 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
6 -import com.baomidou.mybatisplus.core.metadata.TableInfo;  
7 -import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;  
8 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; 6 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
9 import lombok.AllArgsConstructor; 7 import lombok.AllArgsConstructor;
10 import net.sf.jsqlparser.expression.Expression; 8 import net.sf.jsqlparser.expression.Expression;
@@ -27,13 +25,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler { @@ -27,13 +25,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
27 25
28 @Override 26 @Override
29 public boolean ignoreTable(String tableName) { 27 public boolean ignoreTable(String tableName) {
30 - // 如果实体类继承 TenantBaseDO 类,则是多租户表,不进行忽略  
31 - TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName);  
32 - if (tableInfo != null && TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {  
33 - return false;  
34 - }  
35 - // 不包含,说明要过滤  
36 - return !CollUtil.contains(properties.getTables(), tableName); 28 + return CollUtil.contains(properties.getIgnoreTables(), tableName);
37 } 29 }
38 30
39 } 31 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java
1 package cn.iocoder.yudao.framework.tenant.core.security; 1 package cn.iocoder.yudao.framework.tenant.core.security;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; 4 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
6 import cn.iocoder.yudao.framework.security.core.LoginUser; 7 import cn.iocoder.yudao.framework.security.core.LoginUser;
7 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; 8 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  9 +import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
8 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 10 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  11 +import cn.iocoder.yudao.framework.web.config.WebProperties;
  12 +import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
9 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
10 -import org.springframework.web.filter.OncePerRequestFilter; 14 +import org.springframework.util.AntPathMatcher;
11 15
12 import javax.servlet.FilterChain; 16 import javax.servlet.FilterChain;
13 import javax.servlet.ServletException; 17 import javax.servlet.ServletException;
@@ -18,34 +22,72 @@ import java.util.Objects; @@ -18,34 +22,72 @@ import java.util.Objects;
18 22
19 /** 23 /**
20 * 多租户 Security Web 过滤器 24 * 多租户 Security Web 过滤器
21 - * 校验用户访问的租户,是否是其所在的租户,避免越权问题 25 + * 1. 如果是登陆的用户,校验是否有权限访问该租户,避免越权问题。
  26 + * 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。
  27 + *
  28 + * 校验用户访问的租户,是否是其所在的租户,
22 * 29 *
23 * @author 芋道源码 30 * @author 芋道源码
24 */ 31 */
25 @Slf4j 32 @Slf4j
26 -public class TenantSecurityWebFilter extends OncePerRequestFilter { 33 +public class TenantSecurityWebFilter extends ApiRequestFilter {
  34 +
  35 + private final TenantProperties tenantProperties;
  36 + private final AntPathMatcher pathMatcher;
  37 +
  38 + public TenantSecurityWebFilter(TenantProperties tenantProperties,
  39 + WebProperties webProperties) {
  40 + super(webProperties);
  41 + this.tenantProperties = tenantProperties;
  42 + this.pathMatcher = new AntPathMatcher();
  43 + }
27 44
28 @Override 45 @Override
29 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) 46 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
30 throws ServletException, IOException { 47 throws ServletException, IOException {
  48 + Long tenantId = TenantContextHolder.getTenantId();
  49 + // 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。
31 LoginUser user = SecurityFrameworkUtils.getLoginUser(); 50 LoginUser user = SecurityFrameworkUtils.getLoginUser();
32 - assert user != null; // shouldNotFilter 已经校验  
33 - // 校验租户是否匹配。  
34 - if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {  
35 - log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",  
36 - user.getTenantId(), user.getId(), user.getUserType(),  
37 - TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());  
38 - ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.FORBIDDEN.getCode(),  
39 - "您无权访问该租户的数据")); 51 + if (user != null) {
  52 + // 如果获取不到租户编号,则尝试使用登陆用户的租户编号
  53 + if (tenantId == null) {
  54 + tenantId = user.getTenantId();
  55 + TenantContextHolder.setTenantId(tenantId);
  56 + // 如果传递了租户编号,则进行比对租户编号,避免越权问题
  57 + } else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
  58 + log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
  59 + user.getTenantId(), user.getId(), user.getUserType(),
  60 + TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
  61 + ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.FORBIDDEN.getCode(),
  62 + "您无权访问该租户的数据"));
  63 + return;
  64 + }
  65 + }
  66 +
  67 + // 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。
  68 + if (tenantId == null && !isIgnoreUrl(request)) {
  69 + log.error("[doFilterInternal][URL({}/{}) 未传递租户编号]", request.getRequestURI(), request.getMethod());
  70 + ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
  71 + "租户的请求未传递,请进行排查"));
40 return; 72 return;
41 } 73 }
  74 +
42 // 继续过滤 75 // 继续过滤
43 chain.doFilter(request, response); 76 chain.doFilter(request, response);
44 } 77 }
45 78
46 - @Override  
47 - protected boolean shouldNotFilter(HttpServletRequest request) {  
48 - return SecurityFrameworkUtils.getLoginUser() == null; 79 + private boolean isIgnoreUrl(HttpServletRequest request) {
  80 + // 快速匹配,保证性能
  81 + if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
  82 + return true;
  83 + }
  84 + // 逐个 Ant 路径匹配
  85 + for (String url : tenantProperties.getIgnoreUrls()) {
  86 + if (pathMatcher.match(url, request.getRequestURI())) {
  87 + return true;
  88 + }
  89 + }
  90 + return false;
49 } 91 }
50 92
51 } 93 }
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java
@@ -8,15 +8,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties @@ -8,15 +8,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
8 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Bean;
9 import org.springframework.context.annotation.Configuration; 9 import org.springframework.context.annotation.Configuration;
10 import org.springframework.http.HttpHeaders; 10 import org.springframework.http.HttpHeaders;
11 -import springfox.documentation.RequestHandler;  
12 import springfox.documentation.builders.ApiInfoBuilder; 11 import springfox.documentation.builders.ApiInfoBuilder;
13 import springfox.documentation.builders.PathSelectors; 12 import springfox.documentation.builders.PathSelectors;
14 -import springfox.documentation.service.ApiInfo;  
15 -import springfox.documentation.service.ApiKey;  
16 -import springfox.documentation.service.AuthorizationScope;  
17 -import springfox.documentation.service.Contact;  
18 -import springfox.documentation.service.SecurityReference;  
19 -import springfox.documentation.service.SecurityScheme; 13 +import springfox.documentation.service.*;
20 import springfox.documentation.spi.DocumentationType; 14 import springfox.documentation.spi.DocumentationType;
21 import springfox.documentation.spi.service.contexts.SecurityContext; 15 import springfox.documentation.spi.service.contexts.SecurityContext;
22 import springfox.documentation.spring.web.plugins.Docket; 16 import springfox.documentation.spring.web.plugins.Docket;
@@ -24,7 +18,6 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2; @@ -24,7 +18,6 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
24 18
25 import java.util.Collections; 19 import java.util.Collections;
26 import java.util.List; 20 import java.util.List;
27 -import java.util.function.Predicate;  
28 21
29 import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; 22 import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
30 23
@@ -37,8 +30,8 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka @@ -37,8 +30,8 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka
37 @EnableSwagger2 30 @EnableSwagger2
38 @EnableKnife4j 31 @EnableKnife4j
39 @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) 32 @ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
40 -@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)  
41 // 允许使用 swagger.enable=false 禁用 Swagger 33 // 允许使用 swagger.enable=false 禁用 Swagger
  34 +@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
42 @EnableConfigurationProperties(SwaggerProperties.class) 35 @EnableConfigurationProperties(SwaggerProperties.class)
43 public class YudaoSwaggerAutoConfiguration { 36 public class YudaoSwaggerAutoConfiguration {
44 37
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.web.core.filter;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.web.config.WebProperties;
  5 +import lombok.RequiredArgsConstructor;
  6 +import org.springframework.web.filter.OncePerRequestFilter;
  7 +
  8 +import javax.servlet.http.HttpServletRequest;
  9 +
  10 +/**
  11 + * 过滤 /admin-api、/app-api 等 API 请求的过滤器
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@RequiredArgsConstructor
  16 +public abstract class ApiRequestFilter extends OncePerRequestFilter {
  17 +
  18 + protected final WebProperties webProperties;
  19 +
  20 + @Override
  21 + protected boolean shouldNotFilter(HttpServletRequest request) {
  22 + // 只过滤 API 请求的地址
  23 + return !StrUtil.startWithAny(request.getRequestURI(), webProperties.getAdminApi().getPrefix(),
  24 + webProperties.getAppApi().getPrefix());
  25 + }
  26 +
  27 +}
yudao-module-infra/yudao-module-infra-impl/pom.xml
@@ -39,10 +39,6 @@ @@ -39,10 +39,6 @@
39 <groupId>cn.iocoder.boot</groupId> 39 <groupId>cn.iocoder.boot</groupId>
40 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> 40 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
41 </dependency> 41 </dependency>
42 - <dependency>  
43 - <groupId>cn.iocoder.boot</groupId>  
44 - <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>  
45 - </dependency>  
46 42
47 <!-- Web 相关 --> 43 <!-- Web 相关 -->
48 <dependency> 44 <dependency>
@@ -67,6 +63,12 @@ @@ -67,6 +63,12 @@
67 <artifactId>yudao-spring-boot-starter-config</artifactId> 63 <artifactId>yudao-spring-boot-starter-config</artifactId>
68 </dependency> 64 </dependency>
69 65
  66 + <!-- Job 定时任务相关 -->
  67 + <dependency>
  68 + <groupId>cn.iocoder.boot</groupId>
  69 + <artifactId>yudao-spring-boot-starter-job</artifactId>
  70 + </dependency>
  71 +
70 <!-- 消息队列相关 --> 72 <!-- 消息队列相关 -->
71 <dependency> 73 <dependency>
72 <groupId>cn.iocoder.boot</groupId> 74 <groupId>cn.iocoder.boot</groupId>
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
@@ -4,7 +4,6 @@ import cn.hutool.core.io.IoUtil; @@ -4,7 +4,6 @@ import cn.hutool.core.io.IoUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
7 -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;  
8 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO;
9 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO; 8 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO;
10 import cn.iocoder.yudao.module.infra.convert.file.FileConvert; 9 import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
@@ -62,7 +61,6 @@ public class FileController { @@ -62,7 +61,6 @@ public class FileController {
62 @ApiOperation("下载文件") 61 @ApiOperation("下载文件")
63 @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class) 62 @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class)
64 public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException { 63 public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
65 - TenantContextHolder.setNullTenantId();  
66 FileDO file = fileService.getFile(path); 64 FileDO file = fileService.getFile(path);
67 if (file == null) { 65 if (file == null) {
68 log.warn("[getFile][path({}) 文件不存在]", path); 66 log.warn("[getFile][path({}) 文件不存在]", path);
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
1 package cn.iocoder.yudao.module.infra.dal.dataobject.file; 1 package cn.iocoder.yudao.module.infra.dal.dataobject.file;
2 2
3 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import com.baomidou.mybatisplus.annotation.IdType; 4 import com.baomidou.mybatisplus.annotation.IdType;
5 import com.baomidou.mybatisplus.annotation.TableField; 5 import com.baomidou.mybatisplus.annotation.TableField;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
@@ -21,7 +21,7 @@ import java.io.InputStream; @@ -21,7 +21,7 @@ import java.io.InputStream;
21 @Builder 21 @Builder
22 @NoArgsConstructor 22 @NoArgsConstructor
23 @AllArgsConstructor 23 @AllArgsConstructor
24 -public class FileDO extends TenantBaseDO { 24 +public class FileDO extends BaseDO {
25 25
26 /** 26 /**
27 * 文件路径 27 * 文件路径
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiAccessLogDO.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.logger; @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 5 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
8 import lombok.*; 8 import lombok.*;
@@ -21,7 +21,7 @@ import java.util.Date; @@ -21,7 +21,7 @@ import java.util.Date;
21 @Builder 21 @Builder
22 @NoArgsConstructor 22 @NoArgsConstructor
23 @AllArgsConstructor 23 @AllArgsConstructor
24 -public class ApiAccessLogDO extends TenantBaseDO { 24 +public class ApiAccessLogDO extends BaseDO {
25 25
26 /** 26 /**
27 * 编号 27 * 编号
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java
1 package cn.iocoder.yudao.module.infra.dal.dataobject.logger; 1 package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum; 5 import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
@@ -21,7 +21,7 @@ import java.util.Date; @@ -21,7 +21,7 @@ import java.util.Date;
21 @Builder 21 @Builder
22 @NoArgsConstructor 22 @NoArgsConstructor
23 @AllArgsConstructor 23 @AllArgsConstructor
24 -public class ApiErrorLogDO extends TenantBaseDO { 24 +public class ApiErrorLogDO extends BaseDO {
25 25
26 /** 26 /**
27 * 编号 27 * 编号
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java
@@ -54,8 +54,9 @@ public class LoginLogCreateReqDTO { @@ -54,8 +54,9 @@ public class LoginLogCreateReqDTO {
54 private String userIp; 54 private String userIp;
55 /** 55 /**
56 * 浏览器 UserAgent 56 * 浏览器 UserAgent
  57 + *
  58 + * 允许空,原因:Job 过期登出时,是无法传递 UserAgent 的
57 */ 59 */
58 - @NotEmpty(message = "浏览器 UserAgent 不能为空")  
59 private String userAgent; 60 private String userAgent;
60 61
61 } 62 }
yudao-module-system/yudao-module-system-impl/pom.xml
@@ -53,11 +53,11 @@ @@ -53,11 +53,11 @@
53 </dependency> 53 </dependency>
54 <dependency> 54 <dependency>
55 <groupId>cn.iocoder.boot</groupId> 55 <groupId>cn.iocoder.boot</groupId>
56 - <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> 56 + <artifactId>yudao-spring-boot-starter-biz-social</artifactId>
57 </dependency> 57 </dependency>
58 <dependency> 58 <dependency>
59 <groupId>cn.iocoder.boot</groupId> 59 <groupId>cn.iocoder.boot</groupId>
60 - <artifactId>yudao-spring-boot-starter-biz-social</artifactId> 60 + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
61 </dependency> 61 </dependency>
62 62
63 <!-- Web 相关 --> 63 <!-- Web 相关 -->
@@ -77,6 +77,12 @@ @@ -77,6 +77,12 @@
77 <artifactId>yudao-spring-boot-starter-redis</artifactId> 77 <artifactId>yudao-spring-boot-starter-redis</artifactId>
78 </dependency> 78 </dependency>
79 79
  80 + <!-- Job 定时任务相关 -->
  81 + <dependency>
  82 + <groupId>cn.iocoder.boot</groupId>
  83 + <artifactId>yudao-spring-boot-starter-job</artifactId>
  84 + </dependency>
  85 +
80 <!-- 消息队列相关 --> 86 <!-- 消息队列相关 -->
81 <dependency> 87 <dependency>
82 <groupId>cn.iocoder.boot</groupId> 88 <groupId>cn.iocoder.boot</groupId>
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/UserSessionDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.auth; 1 package cn.iocoder.yudao.module.system.dal.dataobject.auth;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.framework.security.core.LoginUser; 5 import cn.iocoder.yudao.framework.security.core.LoginUser;
5 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;  
6 import com.baomidou.mybatisplus.annotation.IdType; 6 import com.baomidou.mybatisplus.annotation.IdType;
7 import com.baomidou.mybatisplus.annotation.TableId; 7 import com.baomidou.mybatisplus.annotation.TableId;
8 import com.baomidou.mybatisplus.annotation.TableName; 8 import com.baomidou.mybatisplus.annotation.TableName;
@@ -25,7 +25,7 @@ import java.util.Date; @@ -25,7 +25,7 @@ import java.util.Date;
25 @Data 25 @Data
26 @Builder 26 @Builder
27 @EqualsAndHashCode(callSuper = true) 27 @EqualsAndHashCode(callSuper = true)
28 -public class UserSessionDO extends TenantBaseDO { 28 +public class UserSessionDO extends BaseDO {
29 29
30 /** 30 /**
31 * 会话编号, 即 sessionId 31 * 会话编号, 即 sessionId
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.dept; 1 package cn.iocoder.yudao.module.system.dal.dataobject.dept;
2 2
3 -import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
8 import lombok.Data; 8 import lombok.Data;
@@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode; @@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode;
17 @TableName("system_dept") 17 @TableName("system_dept")
18 @Data 18 @Data
19 @EqualsAndHashCode(callSuper = true) 19 @EqualsAndHashCode(callSuper = true)
20 -public class DeptDO extends TenantBaseDO { 20 +public class DeptDO extends BaseDO {
21 21
22 /** 22 /**
23 * 部门ID 23 * 部门ID
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.dept; 1 package cn.iocoder.yudao.module.system.dal.dataobject.dept;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 import com.baomidou.mybatisplus.annotation.TableId; 5 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
7 import lombok.Data; 7 import lombok.Data;
@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode; @@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
15 @TableName("system_post") 15 @TableName("system_post")
16 @Data 16 @Data
17 @EqualsAndHashCode(callSuper = true) 17 @EqualsAndHashCode(callSuper = true)
18 -public class PostDO extends TenantBaseDO { 18 +public class PostDO extends BaseDO {
19 19
20 /** 20 /**
21 * 岗位序号 21 * 岗位序号
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.system.dal.dataobject.logger; @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.system.dal.dataobject.logger;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum; 6 import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
6 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;  
7 import com.baomidou.mybatisplus.annotation.TableField; 7 import com.baomidou.mybatisplus.annotation.TableField;
8 import com.baomidou.mybatisplus.annotation.TableId; 8 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 9 import com.baomidou.mybatisplus.annotation.TableName;
@@ -22,7 +22,7 @@ import java.util.Map; @@ -22,7 +22,7 @@ import java.util.Map;
22 @TableName(value = "system_operate_log", autoResultMap = true) 22 @TableName(value = "system_operate_log", autoResultMap = true)
23 @Data 23 @Data
24 @EqualsAndHashCode(callSuper = true) 24 @EqualsAndHashCode(callSuper = true)
25 -public class OperateLogDO extends TenantBaseDO { 25 +public class OperateLogDO extends BaseDO {
26 26
27 /** 27 /**
28 * {@link #javaMethodArgs} 的最大长度 28 * {@link #javaMethodArgs} 的最大长度
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.notice; 1 package cn.iocoder.yudao.module.system.dal.dataobject.notice;
2 2
3 -import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum;
6 import com.baomidou.mybatisplus.annotation.TableField; 6 import com.baomidou.mybatisplus.annotation.TableField;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
8 import lombok.Data; 8 import lombok.Data;
@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode; @@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
16 @TableName("system_notice") 16 @TableName("system_notice")
17 @Data 17 @Data
18 @EqualsAndHashCode(callSuper = true) 18 @EqualsAndHashCode(callSuper = true)
19 -public class NoticeDO extends TenantBaseDO { 19 +public class NoticeDO extends BaseDO {
20 20
21 /** 21 /**
22 * 公告ID 22 * 公告ID
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.user; 1 package cn.iocoder.yudao.module.system.dal.dataobject.user;
2 2
3 -import cn.iocoder.yudao.module.system.enums.common.SexEnum;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; 4 import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
6 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 5 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
  6 +import cn.iocoder.yudao.module.system.enums.common.SexEnum;
7 import com.baomidou.mybatisplus.annotation.TableField; 7 import com.baomidou.mybatisplus.annotation.TableField;
8 import com.baomidou.mybatisplus.annotation.TableId; 8 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 9 import com.baomidou.mybatisplus.annotation.TableName;
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/job/auth/UserSessionTimeoutJob.java
@@ -19,12 +19,12 @@ import javax.annotation.Resource; @@ -19,12 +19,12 @@ import javax.annotation.Resource;
19 public class UserSessionTimeoutJob implements JobHandler { 19 public class UserSessionTimeoutJob implements JobHandler {
20 20
21 @Resource 21 @Resource
22 - private UserSessionService sysUserSessionService; 22 + private UserSessionService userSessionService;
23 23
24 @Override 24 @Override
25 public String execute(String param) throws Exception { 25 public String execute(String param) throws Exception {
26 // 执行过期 26 // 执行过期
27 - Long timeoutCount = sysUserSessionService.clearSessionTimeout(); 27 + Long timeoutCount = userSessionService.clearSessionTimeout();
28 // 返回结果,记录每次的超时数量 28 // 返回结果,记录每次的超时数量
29 return String.format("移除在线会话数量为 %s 个", timeoutCount); 29 return String.format("移除在线会话数量为 %s 个", timeoutCount);
30 } 30 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
@@ -146,7 +146,7 @@ public class PermissionServiceImpl implements PermissionService { @@ -146,7 +146,7 @@ public class PermissionServiceImpl implements PermissionService {
146 public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, 146 public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,
147 Collection<Integer> menusStatuses) { 147 Collection<Integer> menusStatuses) {
148 // 任一一个参数为空时,不返回任何菜单 148 // 任一一个参数为空时,不返回任何菜单
149 - if (CollectionUtils.isAnyEmpty(roleIds, menusStatuses, menusStatuses)) { 149 + if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) {
150 return Collections.emptyList(); 150 return Collections.emptyList();
151 } 151 }
152 // 判断角色是否包含管理员 152 // 判断角色是否包含管理员
yudao-module-tool/yudao-module-tool-impl/pom.xml
@@ -38,10 +38,6 @@ @@ -38,10 +38,6 @@
38 <groupId>cn.iocoder.boot</groupId> 38 <groupId>cn.iocoder.boot</groupId>
39 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> 39 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
40 </dependency> 40 </dependency>
41 - <dependency>  
42 - <groupId>cn.iocoder.boot</groupId>  
43 - <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>  
44 - </dependency>  
45 41
46 <!-- Web 相关 --> 42 <!-- Web 相关 -->
47 <dependency> 43 <dependency>
yudao-module-tool/yudao-module-tool-impl/src/main/java/cn/iocoder/yudao/module/tool/service/codegen/inner/CodegenBuilder.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.tool.service.codegen.inner; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.tool.service.codegen.inner;
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.hutool.core.util.ReflectUtil; 4 import cn.hutool.core.util.ReflectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 6 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
7 import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert; 7 import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert;
8 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO; 8 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
9 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO; 9 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
@@ -60,7 +60,7 @@ public class CodegenBuilder { @@ -60,7 +60,7 @@ public class CodegenBuilder {
60 */ 60 */
61 public static final String TENANT_ID_FIELD = "tenant_id"; 61 public static final String TENANT_ID_FIELD = "tenant_id";
62 /** 62 /**
63 - * {@link TenantBaseDO} 的字段 63 + * {@link cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO} 的字段
64 */ 64 */
65 public static final Set<String> BASE_DO_FIELDS = new HashSet<>(); 65 public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
66 /** 66 /**
@@ -96,7 +96,8 @@ public class CodegenBuilder { @@ -96,7 +96,8 @@ public class CodegenBuilder {
96 .build(); 96 .build();
97 97
98 static { 98 static {
99 - Arrays.stream(ReflectUtil.getFields(TenantBaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName())); 99 + Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
  100 + BASE_DO_FIELDS.add(TENANT_ID_FIELD);
100 // 处理 OPERATION 相关的字段 101 // 处理 OPERATION 相关的字段
101 CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); 102 CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
102 UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); 103 UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
yudao-module-tool/yudao-module-tool-impl/src/main/java/cn/iocoder/yudao/module/tool/service/codegen/inner/CodegenEngine.java
1 package cn.iocoder.yudao.module.tool.service.codegen.inner; 1 package cn.iocoder.yudao.module.tool.service.codegen.inner;
2 2
3 -import cn.hutool.core.collection.ListUtil;  
4 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
5 -import cn.hutool.core.util.ArrayUtil;  
6 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
7 import cn.hutool.extra.template.TemplateConfig; 5 import cn.hutool.extra.template.TemplateConfig;
8 import cn.hutool.extra.template.TemplateEngine; 6 import cn.hutool.extra.template.TemplateEngine;
@@ -11,23 +9,21 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; @@ -11,23 +9,21 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
11 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 9 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
12 import cn.iocoder.yudao.framework.common.pojo.PageParam; 10 import cn.iocoder.yudao.framework.common.pojo.PageParam;
13 import cn.iocoder.yudao.framework.common.pojo.PageResult; 11 import cn.iocoder.yudao.framework.common.pojo.PageResult;
14 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
15 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;  
16 -import cn.iocoder.yudao.module.tool.enums.codegen.CodegenSceneEnum;  
17 -import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties; 12 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  13 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
18 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 14 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
19 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; 15 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
20 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; 16 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
21 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 17 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
22 -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;  
23 -import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;  
24 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 18 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
25 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 19 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
26 -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 20 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  21 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  22 +import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
27 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO; 23 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
28 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO; 24 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
29 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
30 -import cn.iocoder.yudao.framework.common.util.date.DateUtils; 25 +import cn.iocoder.yudao.module.tool.enums.codegen.CodegenSceneEnum;
  26 +import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
31 import com.google.common.collect.Maps; 27 import com.google.common.collect.Maps;
32 import org.springframework.stereotype.Component; 28 import org.springframework.stereotype.Component;
33 29
@@ -115,7 +111,8 @@ public class CodegenEngine { @@ -115,7 +111,8 @@ public class CodegenEngine {
115 private void initGlobalBindingMap() { 111 private void initGlobalBindingMap() {
116 // 全局配置 112 // 全局配置
117 globalBindingMap.put("basePackage", codegenProperties.getBasePackage()); 113 globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
118 - globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage() + '.' + "framework"); // 用于后续获取测试类的 package 地址 114 + globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage()
  115 + + '.' + "framework"); // 用于后续获取测试类的 package 地址
119 // 全局 Java Bean 116 // 全局 Java Bean
120 globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); 117 globalBindingMap.put("CommonResultClassName", CommonResult.class.getName());
121 globalBindingMap.put("PageResultClassName", PageResult.class.getName()); 118 globalBindingMap.put("PageResultClassName", PageResult.class.getName());
@@ -123,6 +120,7 @@ public class CodegenEngine { @@ -123,6 +120,7 @@ public class CodegenEngine {
123 globalBindingMap.put("PageParamClassName", PageParam.class.getName()); 120 globalBindingMap.put("PageParamClassName", PageParam.class.getName());
124 globalBindingMap.put("DictFormatClassName", DictFormat.class.getName()); 121 globalBindingMap.put("DictFormatClassName", DictFormat.class.getName());
125 // DO 类,独有字段 122 // DO 类,独有字段
  123 + globalBindingMap.put("BaseDOClassName", BaseDO.class.getName());
126 globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS); 124 globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS);
127 globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName()); 125 globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName());
128 globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName()); 126 globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName());
@@ -156,15 +154,6 @@ public class CodegenEngine { @@ -156,15 +154,6 @@ public class CodegenEngine {
156 // permission 前缀 154 // permission 前缀
157 bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase); 155 bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase);
158 156
159 - // 如果多租户,则进行覆盖 DB 独有字段  
160 - if (CollectionUtils.findFirst(columns, column -> column.getColumnName().equals(CodegenBuilder.TENANT_ID_FIELD)) != null) {  
161 - bindingMap.put("BaseDOClassName", TenantBaseDO.class.getName());  
162 - bindingMap.put("BaseDOClassName_simple", TenantBaseDO.class.getSimpleName());  
163 - } else {  
164 - bindingMap.put("BaseDOClassName", BaseDO.class.getName());  
165 - bindingMap.put("BaseDOClassName_simple", BaseDO.class.getSimpleName());  
166 - }  
167 -  
168 // 执行生成 157 // 执行生成
169 final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序 158 final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序
170 TEMPLATES.forEach((vmPath, filePath) -> { 159 TEMPLATES.forEach((vmPath, filePath) -> {
yudao-module-tool/yudao-module-tool-impl/src/main/resources/codegen/java/dal/do.vm
@@ -17,7 +17,7 @@ import ${BaseDOClassName}; @@ -17,7 +17,7 @@ import ${BaseDOClassName};
17 @Builder 17 @Builder
18 @NoArgsConstructor 18 @NoArgsConstructor
19 @AllArgsConstructor 19 @AllArgsConstructor
20 -public class ${table.className}DO extends ${BaseDOClassName_simple} { 20 +public class ${table.className}DO extends BaseDO {
21 21
22 #foreach ($column in $columns) 22 #foreach ($column in $columns)
23 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 23 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
yudao-server/src/main/resources/application.yaml
@@ -78,7 +78,9 @@ yudao: @@ -78,7 +78,9 @@ yudao:
78 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants 78 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
79 - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants 79 - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants
80 tenant: # 多租户相关配置项 80 tenant: # 多租户相关配置项
81 - tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置 81 + enable: true
  82 + ignore-urls: /admin-api/system/captcha/get-image, /admin-api/infra/file/get/*
  83 + ignore-tables: infra_config, infra_file, infra_job, infra_job_log, infra_job_log, system_tenant, system_dict_data, system_dict_type, system_error_code, system_menu, system_role, system_role_menu, system_sms_channel, tool_codegen_column, tool_codegen_table, tool_test_demo
82 sms-code: # 短信验证码相关的配置项 84 sms-code: # 短信验证码相关的配置项
83 expire-times: 10m 85 expire-times: 10m
84 send-frequency: 1m 86 send-frequency: 1m
yudao-ui-admin/.env.development
@@ -10,3 +10,6 @@ VUE_APP_BASE_API = &#39;/dev-api&#39; @@ -10,3 +10,6 @@ VUE_APP_BASE_API = &#39;/dev-api&#39;
10 10
11 # 路由懒加载 11 # 路由懒加载
12 VUE_CLI_BABEL_TRANSPILE_MODULES = true 12 VUE_CLI_BABEL_TRANSPILE_MODULES = true
  13 +
  14 +# 多租户的开关
  15 +VUE_APP_TENANT_ENABLE = true
yudao-ui-admin/src/utils/request.js
@@ -4,6 +4,7 @@ import store from &#39;@/store&#39; @@ -4,6 +4,7 @@ import store from &#39;@/store&#39;
4 import { getToken } from '@/utils/auth' 4 import { getToken } from '@/utils/auth'
5 import errorCode from '@/utils/errorCode' 5 import errorCode from '@/utils/errorCode'
6 import Cookies from "js-cookie"; 6 import Cookies from "js-cookie";
  7 +import {getTenantEnable} from "@/utils/ruoyi";
7 8
8 // 是否显示重新登录 9 // 是否显示重新登录
9 let isReloginShow; 10 let isReloginShow;
@@ -24,9 +25,11 @@ service.interceptors.request.use(config =&gt; { @@ -24,9 +25,11 @@ service.interceptors.request.use(config =&gt; {
24 config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 25 config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
25 } 26 }
26 // 设置租户 27 // 设置租户
27 - const tenantId = Cookies.get('tenantId');  
28 - if (tenantId) {  
29 - config.headers['tenant-id'] = tenantId; 28 + if (getTenantEnable()) {
  29 + const tenantId = Cookies.get('tenantId');
  30 + if (tenantId) {
  31 + config.headers['tenant-id'] = tenantId;
  32 + }
30 } 33 }
31 // get请求映射params参数 34 // get请求映射params参数
32 if (config.method === 'get' && config.params) { 35 if (config.method === 'get' && config.params) {
yudao-ui-admin/src/utils/ruoyi.js
@@ -170,3 +170,17 @@ export function getNowDateTime(timeStr) { @@ -170,3 +170,17 @@ export function getNowDateTime(timeStr) {
170 let seconds = now.getSeconds().toString().padStart(2, "0") // 得到秒; 170 let seconds = now.getSeconds().toString().padStart(2, "0") // 得到秒;
171 return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; 171 return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
172 } 172 }
  173 +
  174 +/**
  175 + * 获得租户功能是否开启
  176 + */
  177 +export function getTenantEnable() {
  178 + console.log("enable: " + process.env.VUE_APP_TENANT_ENABLE)
  179 + if (process.env.VUE_APP_TENANT_ENABLE === "true") {
  180 + return true;
  181 + }
  182 + if (process.env.VUE_APP_TENANT_ENABLE === "false") {
  183 + return false;
  184 + }
  185 + return process.env.VUE_APP_TENANT_ENABLE || true;
  186 +}
yudao-ui-admin/src/views/login.vue
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 <div class="login"> 2 <div class="login">
3 <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> 3 <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
4 <h3 class="title">芋道后台管理系统</h3> 4 <h3 class="title">芋道后台管理系统</h3>
5 - <el-form-item prop="tenantName"> 5 + <el-form-item prop="tenantName" v-if="tenantEnable">
6 <el-input v-model="loginForm.tenantName" type="text" auto-complete="off" placeholder='租户'> 6 <el-input v-model="loginForm.tenantName" type="text" auto-complete="off" placeholder='租户'>
7 <svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon" /> 7 <svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon" />
8 </el-input> 8 </el-input>
@@ -54,7 +54,8 @@ import { getCodeImg,socialAuthRedirect } from &quot;@/api/login&quot;; @@ -54,7 +54,8 @@ import { getCodeImg,socialAuthRedirect } from &quot;@/api/login&quot;;
54 import { getTenantIdByName } from "@/api/system/tenant"; 54 import { getTenantIdByName } from "@/api/system/tenant";
55 import Cookies from "js-cookie"; 55 import Cookies from "js-cookie";
56 import { encrypt, decrypt } from '@/utils/jsencrypt' 56 import { encrypt, decrypt } from '@/utils/jsencrypt'
57 -import {InfraApiErrorLogProcessStatusEnum, SystemUserSocialTypeEnum} from "@/utils/constants"; 57 +import {SystemUserSocialTypeEnum} from "@/utils/constants";
  58 +import { getTenantEnable } from "@/utils/ruoyi";
58 59
59 export default { 60 export default {
60 name: "Login", 61 name: "Login",
@@ -62,6 +63,7 @@ export default { @@ -62,6 +63,7 @@ export default {
62 return { 63 return {
63 codeUrl: "", 64 codeUrl: "",
64 captchaEnable: true, 65 captchaEnable: true,
  66 + tenantEnable: true,
65 loginForm: { 67 loginForm: {
66 username: "admin", 68 username: "admin",
67 password: "admin123", 69 password: "admin123",
@@ -71,6 +73,13 @@ export default { @@ -71,6 +73,13 @@ export default {
71 tenantName: "芋道源码", 73 tenantName: "芋道源码",
72 }, 74 },
73 loginRules: { 75 loginRules: {
  76 + username: [
  77 + { required: true, trigger: "blur", message: "用户名不能为空" }
  78 + ],
  79 + password: [
  80 + { required: true, trigger: "blur", message: "密码不能为空" }
  81 + ],
  82 + code: [{ required: true, trigger: "change", message: "验证码不能为空" }],
74 tenantName: [ 83 tenantName: [
75 { required: true, trigger: "blur", message: "租户不能为空" }, 84 { required: true, trigger: "blur", message: "租户不能为空" },
76 { 85 {
@@ -90,13 +99,6 @@ export default { @@ -90,13 +99,6 @@ export default {
90 trigger: 'blur' 99 trigger: 'blur'
91 } 100 }
92 ], 101 ],
93 - username: [  
94 - { required: true, trigger: "blur", message: "用户名不能为空" }  
95 - ],  
96 - password: [  
97 - { required: true, trigger: "blur", message: "密码不能为空" }  
98 - ],  
99 - code: [{ required: true, trigger: "change", message: "验证码不能为空" }]  
100 }, 102 },
101 loading: false, 103 loading: false,
102 redirect: undefined, 104 redirect: undefined,
@@ -113,6 +115,8 @@ export default { @@ -113,6 +115,8 @@ export default {
113 // } 115 // }
114 // }, 116 // },
115 created() { 117 created() {
  118 + // 租户开关
  119 + this.tenantEnable = getTenantEnable();
116 // 重定向地址 120 // 重定向地址
117 this.redirect = this.$route.query.redirect; 121 this.redirect = this.$route.query.redirect;
118 this.getCode(); 122 this.getCode();