Kaynağa Gözat

* 【新增】后端 `yudao.tenant.enable` 配置项,前端 `VUE_APP_TENANT_ENABLE` 配置项,用于开关租户功能
* 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略
* 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API

YunaiV 3 yıl önce
ebeveyn
işleme
79311ecc71
36 değiştirilmiş dosya ile 220 ekleme ve 122 silme
  1. 1 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
  2. 19 13
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java
  3. 3 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantDatabaseAutoConfiguration.java
  4. 3 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantJobAutoConfiguration.java
  5. 3 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantMQAutoConfiguration.java
  6. 9 2
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantSecurityAutoConfiguration.java
  7. 3 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantWebAutoConfiguration.java
  8. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java
  9. 1 9
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
  10. 56 14
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java
  11. 2 9
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java
  12. 27 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java
  13. 6 4
      yudao-module-infra/yudao-module-infra-impl/pom.xml
  14. 0 2
      yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
  15. 2 2
      yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
  16. 2 2
      yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiAccessLogDO.java
  17. 2 2
      yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java
  18. 2 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java
  19. 8 2
      yudao-module-system/yudao-module-system-impl/pom.xml
  20. 2 2
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/UserSessionDO.java
  21. 3 3
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java
  22. 2 2
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java
  23. 2 2
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java
  24. 3 3
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java
  25. 1 1
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
  26. 2 2
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/job/auth/UserSessionTimeoutJob.java
  27. 1 1
      yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
  28. 0 4
      yudao-module-tool/yudao-module-tool-impl/pom.xml
  29. 4 3
      yudao-module-tool/yudao-module-tool-impl/src/main/java/cn/iocoder/yudao/module/tool/service/codegen/inner/CodegenBuilder.java
  30. 10 21
      yudao-module-tool/yudao-module-tool-impl/src/main/java/cn/iocoder/yudao/module/tool/service/codegen/inner/CodegenEngine.java
  31. 1 1
      yudao-module-tool/yudao-module-tool-impl/src/main/resources/codegen/java/dal/do.vm
  32. 3 1
      yudao-server/src/main/resources/application.yaml
  33. 3 0
      yudao-ui-admin/.env.development
  34. 6 3
      yudao-ui-admin/src/utils/request.js
  35. 14 0
      yudao-ui-admin/src/utils/ruoyi.js
  36. 13 9
      yudao-ui-admin/src/views/login.vue

+ 1 - 1
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;
 /**
  * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
  *
- * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
+ *  考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
  *
  * @author 芋道源码
  */

+ 19 - 13
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;
 @Data
 public class TenantProperties {
 
-//    /**
-//     * 租户是否开启
-//     */
-//    private static final Boolean ENABLE_DEFAULT = true;
-//
-//    /**
-//     * 是否开启
-//     */
-//    private Boolean enable = ENABLE_DEFAULT;
+    /**
+     * 租户是否开启
+     */
+    private static final Boolean ENABLE_DEFAULT = true;
+
+    /**
+     * 是否开启
+     */
+    private Boolean enable = ENABLE_DEFAULT;
+
+    /**
+     * 需要忽略多租户的请求
+     *
+     * 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!
+     */
+    private Set<String> ignoreUrls;
 
     /**
-     * 需要多租户的表
+     * 需要忽略多租户的表
      *
-     * 由于多租户并不作为 yudao 项目的重点功能,更多是扩展性的功能,所以采用正向配置需要多租户的表。
-     * 如果需要,你可以改成 ignoreTables 来取消部分不需要的表
+     * 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
      */
-    private Set<String> tables;
+    private Set<String> ignoreTables;
 
 }

+ 3 - 0
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;
 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -14,6 +15,8 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
+// 允许使用 yudao.tenant.enable=false 禁用多租户
+@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
 @EnableConfigurationProperties(TenantProperties.class)
 public class YudaoTenantDatabaseAutoConfiguration {
 

+ 3 - 0
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;
 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
+// 允许使用 yudao.tenant.enable=false 禁用多租户
+@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
 public class YudaoTenantJobAutoConfiguration {
 
     @Bean

+ 3 - 0
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantMQAutoConfiguration.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.framework.tenant.config;
 
 import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -10,6 +11,8 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
+// 允许使用 yudao.tenant.enable=false 禁用多租户
+@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
 public class YudaoTenantMQAutoConfiguration {
 
     @Bean

+ 9 - 2
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;
 
 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
+import cn.iocoder.yudao.framework.web.config.WebProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -12,12 +15,16 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
+// 允许使用 yudao.tenant.enable=false 禁用多租户
+@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
+@EnableConfigurationProperties(TenantProperties.class)
 public class YudaoTenantSecurityAutoConfiguration {
 
     @Bean
-    public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter() {
+    public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter(TenantProperties tenantProperties,
+                                                                                   WebProperties webProperties) {
         FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>();
-        registrationBean.setFilter(new TenantSecurityWebFilter());
+        registrationBean.setFilter(new TenantSecurityWebFilter(tenantProperties, webProperties));
         registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER);
         return registrationBean;
     }

+ 3 - 0
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;
 
 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
 import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -12,6 +13,8 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
+// 允许使用 yudao.tenant.enable=false 禁用多租户
+@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
 public class YudaoTenantWebAutoConfiguration {
 
     @Bean

+ 1 - 1
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 {
     public static Long getRequiredTenantId() {
         Long tenantId = getTenantId();
         if (tenantId == null) {
-            throw new NullPointerException("TenantContextHolder 不存在租户编号");
+            throw new NullPointerException("TenantContextHolder 不存在租户编号"); // TODO 芋艿:增加文档链接
         }
         return tenantId;
     }

+ 1 - 9
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;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
-import com.baomidou.mybatisplus.core.metadata.TableInfo;
-import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
 import lombok.AllArgsConstructor;
 import net.sf.jsqlparser.expression.Expression;
@@ -27,13 +25,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
 
     @Override
     public boolean ignoreTable(String tableName) {
-        // 如果实体类继承 TenantBaseDO 类,则是多租户表,不进行忽略
-        TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName);
-        if (tableInfo != null && TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {
-            return false;
-        }
-        // 不包含,说明要过滤
-        return !CollUtil.contains(properties.getTables(), tableName);
+        return CollUtil.contains(properties.getIgnoreTables(), tableName);
     }
 
 }

+ 56 - 14
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java

@@ -1,13 +1,17 @@
 package cn.iocoder.yudao.framework.tenant.core.security;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.framework.web.config.WebProperties;
+import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.util.AntPathMatcher;
 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
@@ -18,34 +22,72 @@ import java.util.Objects;
 
 /**
  * 多租户 Security Web 过滤器
- * 校验用户访问的租户,是否是其所在的租户,避免越权问题
+ * 1. 如果是登陆的用户,校验是否有权限访问该租户,避免越权问题。
+ * 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。
+ *
+ * 校验用户访问的租户,是否是其所在的租户,
  *
  * @author 芋道源码
  */
 @Slf4j
-public class TenantSecurityWebFilter extends OncePerRequestFilter {
+public class TenantSecurityWebFilter extends ApiRequestFilter {
+
+    private final TenantProperties tenantProperties;
+    private final AntPathMatcher pathMatcher;
+
+    public TenantSecurityWebFilter(TenantProperties tenantProperties,
+                                   WebProperties webProperties) {
+        super(webProperties);
+        this.tenantProperties = tenantProperties;
+        this.pathMatcher = new AntPathMatcher();
+    }
 
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
             throws ServletException, IOException {
+        Long tenantId = TenantContextHolder.getTenantId();
+        // 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。
         LoginUser user = SecurityFrameworkUtils.getLoginUser();
-        assert user != null; // shouldNotFilter 已经校验
-        // 校验租户是否匹配。
-        if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
-            log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
-                    user.getTenantId(), user.getId(), user.getUserType(),
-                    TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
-            ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.FORBIDDEN.getCode(),
-                    "您无权访问该租户的数据"));
+        if (user != null) {
+            // 如果获取不到租户编号,则尝试使用登陆用户的租户编号
+            if (tenantId == null) {
+                tenantId = user.getTenantId();
+                TenantContextHolder.setTenantId(tenantId);
+            // 如果传递了租户编号,则进行比对租户编号,避免越权问题
+            } else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
+                log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
+                        user.getTenantId(), user.getId(), user.getUserType(),
+                        TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
+                ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.FORBIDDEN.getCode(),
+                        "您无权访问该租户的数据"));
+                return;
+            }
+        }
+
+        // 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。
+        if (tenantId == null && !isIgnoreUrl(request)) {
+            log.error("[doFilterInternal][URL({}/{}) 未传递租户编号]", request.getRequestURI(), request.getMethod());
+            ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
+                    "租户的请求未传递,请进行排查"));
             return;
         }
+
         // 继续过滤
         chain.doFilter(request, response);
     }
 
-    @Override
-    protected boolean shouldNotFilter(HttpServletRequest request) {
-        return SecurityFrameworkUtils.getLoginUser() == null;
+    private boolean isIgnoreUrl(HttpServletRequest request) {
+        // 快速匹配,保证性能
+        if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
+            return true;
+        }
+        // 逐个 Ant 路径匹配
+        for (String url : tenantProperties.getIgnoreUrls()) {
+            if (pathMatcher.match(url, request.getRequestURI())) {
+                return true;
+            }
+        }
+        return false;
     }
 
 }

+ 2 - 9
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
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpHeaders;
-import springfox.documentation.RequestHandler;
 import springfox.documentation.builders.ApiInfoBuilder;
 import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.ApiKey;
-import springfox.documentation.service.AuthorizationScope;
-import springfox.documentation.service.Contact;
-import springfox.documentation.service.SecurityReference;
-import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.service.*;
 import springfox.documentation.spi.DocumentationType;
 import springfox.documentation.spi.service.contexts.SecurityContext;
 import springfox.documentation.spring.web.plugins.Docket;
@@ -24,7 +18,6 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.function.Predicate;
 
 import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
 
@@ -37,8 +30,8 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka
 @EnableSwagger2
 @EnableKnife4j
 @ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
-@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
 // 允许使用 swagger.enable=false 禁用 Swagger
+@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
 @EnableConfigurationProperties(SwaggerProperties.class)
 public class YudaoSwaggerAutoConfiguration {
 

+ 27 - 0
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.framework.web.core.filter;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.web.config.WebProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 过滤 /admin-api、/app-api 等 API 请求的过滤器
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+public abstract class ApiRequestFilter extends OncePerRequestFilter {
+
+    protected final WebProperties webProperties;
+
+    @Override
+    protected boolean shouldNotFilter(HttpServletRequest request) {
+        // 只过滤 API 请求的地址
+        return !StrUtil.startWithAny(request.getRequestURI(), webProperties.getAdminApi().getPrefix(),
+                webProperties.getAppApi().getPrefix());
+    }
+
+}

+ 6 - 4
yudao-module-infra/yudao-module-infra-impl/pom.xml

@@ -39,10 +39,6 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
         </dependency>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
-        </dependency>
 
         <!-- Web 相关 -->
         <dependency>
@@ -67,6 +63,12 @@
             <artifactId>yudao-spring-boot-starter-config</artifactId>
         </dependency>
 
+        <!-- Job 定时任务相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-job</artifactId>
+        </dependency>
+
         <!-- 消息队列相关 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 0 - 2
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;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
-import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO;
 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO;
 import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
@@ -62,7 +61,6 @@ public class FileController {
     @ApiOperation("下载文件")
     @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class)
     public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
-        TenantContextHolder.setNullTenantId();
         FileDO file = fileService.getFile(path);
         if (file == null) {
             log.warn("[getFile][path({}) 文件不存在]", path);

+ 2 - 2
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.infra.dal.dataobject.file;
 
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -21,7 +21,7 @@ import java.io.InputStream;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class FileDO extends TenantBaseDO {
+public class FileDO extends BaseDO {
 
     /**
      * 文件路径

+ 2 - 2
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;
 
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.*;
@@ -21,7 +21,7 @@ import java.util.Date;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class ApiAccessLogDO extends TenantBaseDO {
+public class ApiAccessLogDO extends BaseDO {
 
     /**
      * 编号

+ 2 - 2
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
 
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -21,7 +21,7 @@ import java.util.Date;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class ApiErrorLogDO extends TenantBaseDO {
+public class ApiErrorLogDO extends BaseDO {
 
     /**
      * 编号

+ 2 - 1
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 {
     private String userIp;
     /**
      * 浏览器 UserAgent
+     *
+     * 允许空,原因:Job 过期登出时,是无法传递 UserAgent 的
      */
-    @NotEmpty(message = "浏览器 UserAgent 不能为空")
     private String userAgent;
 
 }

+ 8 - 2
yudao-module-system/yudao-module-system-impl/pom.xml

@@ -53,11 +53,11 @@
         </dependency>
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
+            <artifactId>yudao-spring-boot-starter-biz-social</artifactId>
         </dependency>
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-social</artifactId>
+            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
         </dependency>
 
         <!-- Web 相关 -->
@@ -77,6 +77,12 @@
             <artifactId>yudao-spring-boot-starter-redis</artifactId>
         </dependency>
 
+        <!-- Job 定时任务相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-job</artifactId>
+        </dependency>
+
         <!-- 消息队列相关 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 2 - 2
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/UserSessionDO.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.auth;
 
 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.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -25,7 +25,7 @@ import java.util.Date;
 @Data
 @Builder
 @EqualsAndHashCode(callSuper = true)
-public class UserSessionDO extends TenantBaseDO {
+public class UserSessionDO extends BaseDO {
 
     /**
      * 会话编号, 即 sessionId

+ 3 - 3
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.dept;
 
-import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
@@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode;
 @TableName("system_dept")
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class DeptDO extends TenantBaseDO {
+public class DeptDO extends BaseDO {
 
     /**
      * 部门ID

+ 2 - 2
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.dept;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
 @TableName("system_post")
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class PostDO extends TenantBaseDO {
+public class PostDO extends BaseDO {
 
     /**
      * 岗位序号

+ 2 - 2
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;
 
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -22,7 +22,7 @@ import java.util.Map;
 @TableName(value = "system_operate_log", autoResultMap = true)
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class OperateLogDO extends TenantBaseDO {
+public class OperateLogDO extends BaseDO {
 
     /**
      * {@link #javaMethodArgs} 的最大长度

+ 3 - 3
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.notice;
 
-import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
 @TableName("system_notice")
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class NoticeDO extends TenantBaseDO {
+public class NoticeDO extends BaseDO {
 
     /**
      * 公告ID

+ 1 - 1
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.user;
 
-import cn.iocoder.yudao.module.system.enums.common.SexEnum;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.module.system.enums.common.SexEnum;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;

+ 2 - 2
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;
 public class UserSessionTimeoutJob implements JobHandler {
 
     @Resource
-    private UserSessionService sysUserSessionService;
+    private UserSessionService userSessionService;
 
     @Override
     public String execute(String param) throws Exception {
         // 执行过期
-        Long timeoutCount = sysUserSessionService.clearSessionTimeout();
+        Long timeoutCount = userSessionService.clearSessionTimeout();
         // 返回结果,记录每次的超时数量
         return String.format("移除在线会话数量为 %s 个", timeoutCount);
     }

+ 1 - 1
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 {
     public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,
                                               Collection<Integer> menusStatuses) {
         // 任一一个参数为空时,不返回任何菜单
-        if (CollectionUtils.isAnyEmpty(roleIds, menusStatuses, menusStatuses)) {
+        if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) {
             return Collections.emptyList();
         }
         // 判断角色是否包含管理员

+ 0 - 4
yudao-module-tool/yudao-module-tool-impl/pom.xml

@@ -38,10 +38,6 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
         </dependency>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
-        </dependency>
 
         <!-- Web 相关 -->
         <dependency>

+ 4 - 3
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;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert;
 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
@@ -60,7 +60,7 @@ public class CodegenBuilder {
      */
     public static final String TENANT_ID_FIELD = "tenant_id";
     /**
-     * {@link TenantBaseDO} 的字段
+     * {@link cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO} 的字段
      */
     public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
     /**
@@ -96,7 +96,8 @@ public class CodegenBuilder {
             .build();
 
     static {
-        Arrays.stream(ReflectUtil.getFields(TenantBaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
+        Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
+        BASE_DO_FIELDS.add(TENANT_ID_FIELD);
         // 处理 OPERATION 相关的字段
         CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
         UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);

+ 10 - 21
yudao-module-tool/yudao-module-tool-impl/src/main/java/cn/iocoder/yudao/module/tool/service/codegen/inner/CodegenEngine.java

@@ -1,8 +1,6 @@
 package cn.iocoder.yudao.module.tool.service.codegen.inner;
 
-import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.template.TemplateConfig;
 import cn.hutool.extra.template.TemplateEngine;
@@ -11,23 +9,21 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
-import cn.iocoder.yudao.module.tool.enums.codegen.CodegenSceneEnum;
-import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
-import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.common.util.date.DateUtils;
+import cn.iocoder.yudao.module.tool.enums.codegen.CodegenSceneEnum;
+import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
 import com.google.common.collect.Maps;
 import org.springframework.stereotype.Component;
 
@@ -115,7 +111,8 @@ public class CodegenEngine {
     private void initGlobalBindingMap() {
         // 全局配置
         globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
-        globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage() + '.' + "framework"); // 用于后续获取测试类的 package 地址
+        globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage()
+                + '.' + "framework"); // 用于后续获取测试类的 package 地址
         // 全局 Java Bean
         globalBindingMap.put("CommonResultClassName", CommonResult.class.getName());
         globalBindingMap.put("PageResultClassName", PageResult.class.getName());
@@ -123,6 +120,7 @@ public class CodegenEngine {
         globalBindingMap.put("PageParamClassName", PageParam.class.getName());
         globalBindingMap.put("DictFormatClassName", DictFormat.class.getName());
         // DO 类,独有字段
+        globalBindingMap.put("BaseDOClassName", BaseDO.class.getName());
         globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS);
         globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName());
         globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName());
@@ -156,15 +154,6 @@ public class CodegenEngine {
         // permission 前缀
         bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase);
 
-        // 如果多租户,则进行覆盖 DB 独有字段
-        if (CollectionUtils.findFirst(columns, column -> column.getColumnName().equals(CodegenBuilder.TENANT_ID_FIELD)) != null) {
-            bindingMap.put("BaseDOClassName", TenantBaseDO.class.getName());
-            bindingMap.put("BaseDOClassName_simple", TenantBaseDO.class.getSimpleName());
-        } else {
-            bindingMap.put("BaseDOClassName", BaseDO.class.getName());
-            bindingMap.put("BaseDOClassName_simple", BaseDO.class.getSimpleName());
-        }
-
         // 执行生成
         final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序
         TEMPLATES.forEach((vmPath, filePath) -> {

+ 1 - 1
yudao-module-tool/yudao-module-tool-impl/src/main/resources/codegen/java/dal/do.vm

@@ -17,7 +17,7 @@ import ${BaseDOClassName};
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class ${table.className}DO extends ${BaseDOClassName_simple} {
+public class ${table.className}DO extends BaseDO {
 
 #foreach ($column in $columns)
 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段

+ 3 - 1
yudao-server/src/main/resources/application.yaml

@@ -78,7 +78,9 @@ yudao:
       - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
       - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants
   tenant: # 多租户相关配置项
-    tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
+    enable: true
+    ignore-urls: /admin-api/system/captcha/get-image, /admin-api/infra/file/get/*
+    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
   sms-code: # 短信验证码相关的配置项
     expire-times: 10m
     send-frequency: 1m

+ 3 - 0
yudao-ui-admin/.env.development

@@ -10,3 +10,6 @@ VUE_APP_BASE_API = '/dev-api'
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 多租户的开关
+VUE_APP_TENANT_ENABLE = true

+ 6 - 3
yudao-ui-admin/src/utils/request.js

@@ -4,6 +4,7 @@ import store from '@/store'
 import { getToken } from '@/utils/auth'
 import errorCode from '@/utils/errorCode'
 import Cookies from "js-cookie";
+import {getTenantEnable} from "@/utils/ruoyi";
 
 // 是否显示重新登录
 let isReloginShow;
@@ -24,9 +25,11 @@ service.interceptors.request.use(config => {
     config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
   }
   // 设置租户
-  const tenantId = Cookies.get('tenantId');
-  if (tenantId) {
-    config.headers['tenant-id'] = tenantId;
+  if (getTenantEnable()) {
+    const tenantId = Cookies.get('tenantId');
+    if (tenantId) {
+      config.headers['tenant-id'] = tenantId;
+    }
   }
   // get请求映射params参数
   if (config.method === 'get' && config.params) {

+ 14 - 0
yudao-ui-admin/src/utils/ruoyi.js

@@ -170,3 +170,17 @@ export function getNowDateTime(timeStr) {
   let seconds = now.getSeconds().toString().padStart(2, "0") // 得到秒;
   return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
 }
+
+/**
+ * 获得租户功能是否开启
+ */
+export function getTenantEnable() {
+  console.log("enable: " + process.env.VUE_APP_TENANT_ENABLE)
+  if (process.env.VUE_APP_TENANT_ENABLE === "true") {
+    return true;
+  }
+  if (process.env.VUE_APP_TENANT_ENABLE === "false") {
+    return false;
+  }
+  return process.env.VUE_APP_TENANT_ENABLE || true;
+}

+ 13 - 9
yudao-ui-admin/src/views/login.vue

@@ -2,7 +2,7 @@
   <div class="login">
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
       <h3 class="title">芋道后台管理系统</h3>
-      <el-form-item prop="tenantName">
+      <el-form-item prop="tenantName" v-if="tenantEnable">
         <el-input v-model="loginForm.tenantName" type="text" auto-complete="off" placeholder='租户'>
           <svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon" />
         </el-input>
@@ -54,7 +54,8 @@ import { getCodeImg,socialAuthRedirect } from "@/api/login";
 import { getTenantIdByName } from "@/api/system/tenant";
 import Cookies from "js-cookie";
 import { encrypt, decrypt } from '@/utils/jsencrypt'
-import {InfraApiErrorLogProcessStatusEnum, SystemUserSocialTypeEnum} from "@/utils/constants";
+import {SystemUserSocialTypeEnum} from "@/utils/constants";
+import { getTenantEnable } from "@/utils/ruoyi";
 
 export default {
   name: "Login",
@@ -62,6 +63,7 @@ export default {
     return {
       codeUrl: "",
       captchaEnable: true,
+      tenantEnable: true,
       loginForm: {
         username: "admin",
         password: "admin123",
@@ -71,6 +73,13 @@ export default {
         tenantName: "芋道源码",
       },
       loginRules: {
+        username: [
+          { required: true, trigger: "blur", message: "用户名不能为空" }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "密码不能为空" }
+        ],
+        code: [{ required: true, trigger: "change", message: "验证码不能为空" }],
         tenantName: [
           { required: true, trigger: "blur", message: "租户不能为空" },
           {
@@ -90,13 +99,6 @@ export default {
             trigger: 'blur'
           }
         ],
-        username: [
-          { required: true, trigger: "blur", message: "用户名不能为空" }
-        ],
-        password: [
-          { required: true, trigger: "blur", message: "密码不能为空" }
-        ],
-        code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
       },
       loading: false,
       redirect: undefined,
@@ -113,6 +115,8 @@ export default {
   //   }
   // },
   created() {
+    // 租户开关
+    this.tenantEnable = getTenantEnable();
     // 重定向地址
     this.redirect = this.$route.query.redirect;
     this.getCode();