提交 79311ecc 编写于 作者: 公众号-芋道源码's avatar 公众号-芋道源码

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

* 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略
* 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API
上级 27c30279
...@@ -14,22 +14,28 @@ import java.util.Set; ...@@ -14,22 +14,28 @@ import java.util.Set;
@Data @Data
public class TenantProperties { public class TenantProperties {
// /** /**
// * 租户是否开启 * 租户是否开启
// */ */
// private static final Boolean ENABLE_DEFAULT = true; private static final Boolean ENABLE_DEFAULT = true;
//
// /** /**
// * 是否开启 * 是否开启
// */ */
// private Boolean enable = ENABLE_DEFAULT; private Boolean enable = ENABLE_DEFAULT;
/**
* 需要忽略多租户的请求
*
* 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!
*/
private Set<String> ignoreUrls;
/** /**
* 需要多租户的表 * 需要忽略多租户的表
* *
* 由于多租户并不作为 yudao 项目的重点功能,更多是扩展性的功能,所以采用正向配置需要多租户的表。 * 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
* 如果需要,你可以改成 ignoreTables 来取消部分不需要的表
*/ */
private Set<String> tables; private Set<String> ignoreTables;
} }
...@@ -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;
import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; 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.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -14,6 +15,8 @@ import org.springframework.context.annotation.Configuration; ...@@ -14,6 +15,8 @@ import org.springframework.context.annotation.Configuration;
* @author 芋道源码 * @author 芋道源码
*/ */
@Configuration @Configuration
// 允许使用 yudao.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
@EnableConfigurationProperties(TenantProperties.class) @EnableConfigurationProperties(TenantProperties.class)
public class YudaoTenantDatabaseAutoConfiguration { public class YudaoTenantDatabaseAutoConfiguration {
......
...@@ -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;
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration; ...@@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration;
* @author 芋道源码 * @author 芋道源码
*/ */
@Configuration @Configuration
// 允许使用 yudao.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
public class YudaoTenantJobAutoConfiguration { public class YudaoTenantJobAutoConfiguration {
@Bean @Bean
......
package cn.iocoder.yudao.framework.tenant.config; package cn.iocoder.yudao.framework.tenant.config;
import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -10,6 +11,8 @@ import org.springframework.context.annotation.Configuration; ...@@ -10,6 +11,8 @@ import org.springframework.context.annotation.Configuration;
* @author 芋道源码 * @author 芋道源码
*/ */
@Configuration @Configuration
// 允许使用 yudao.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
public class YudaoTenantMQAutoConfiguration { public class YudaoTenantMQAutoConfiguration {
@Bean @Bean
......
...@@ -2,6 +2,9 @@ package cn.iocoder.yudao.framework.tenant.config; ...@@ -2,6 +2,9 @@ package cn.iocoder.yudao.framework.tenant.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; 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.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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;
* @author 芋道源码 * @author 芋道源码
*/ */
@Configuration @Configuration
// 允许使用 yudao.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
@EnableConfigurationProperties(TenantProperties.class)
public class YudaoTenantSecurityAutoConfiguration { public class YudaoTenantSecurityAutoConfiguration {
@Bean @Bean
public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter() { public FilterRegistrationBean<TenantSecurityWebFilter> tenantSecurityWebFilter(TenantProperties tenantProperties,
WebProperties webProperties) {
FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>(); FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TenantSecurityWebFilter()); registrationBean.setFilter(new TenantSecurityWebFilter(tenantProperties, webProperties));
registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER); registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER);
return registrationBean; return registrationBean;
} }
......
...@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.tenant.config; ...@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.tenant.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter; 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.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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;
* @author 芋道源码 * @author 芋道源码
*/ */
@Configuration @Configuration
// 允许使用 yudao.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true)
public class YudaoTenantWebAutoConfiguration { public class YudaoTenantWebAutoConfiguration {
@Bean @Bean
......
...@@ -33,7 +33,7 @@ public class TenantContextHolder { ...@@ -33,7 +33,7 @@ public class TenantContextHolder {
public static Long getRequiredTenantId() { public static Long getRequiredTenantId() {
Long tenantId = getTenantId(); Long tenantId = getTenantId();
if (tenantId == null) { if (tenantId == null) {
throw new NullPointerException("TenantContextHolder 不存在租户编号"); throw new NullPointerException("TenantContextHolder 不存在租户编号"); // TODO 芋艿:增加文档链接
} }
return tenantId; return tenantId;
} }
......
...@@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.tenant.core.db; ...@@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.tenant.core.db;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.tenant.config.TenantProperties; import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 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 com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
...@@ -27,13 +25,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler { ...@@ -27,13 +25,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
@Override @Override
public boolean ignoreTable(String tableName) { public boolean ignoreTable(String tableName) {
// 如果实体类继承 TenantBaseDO 类,则是多租户表,不进行忽略 return CollUtil.contains(properties.getIgnoreTables(), tableName);
TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName);
if (tableInfo != null && TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {
return false;
}
// 不包含,说明要过滤
return !CollUtil.contains(properties.getTables(), tableName);
} }
} }
package cn.iocoder.yudao.framework.tenant.core.security; 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.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; 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.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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.util.AntPathMatcher;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException; import javax.servlet.ServletException;
...@@ -18,20 +22,39 @@ import java.util.Objects; ...@@ -18,20 +22,39 @@ import java.util.Objects;
/** /**
* 多租户 Security Web 过滤器 * 多租户 Security Web 过滤器
* 校验用户访问的租户,是否是其所在的租户,避免越权问题 * 1. 如果是登陆的用户,校验是否有权限访问该租户,避免越权问题。
* 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。
*
* 校验用户访问的租户,是否是其所在的租户,
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Slf4j @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 @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException { throws ServletException, IOException {
Long tenantId = TenantContextHolder.getTenantId();
// 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。
LoginUser user = SecurityFrameworkUtils.getLoginUser(); LoginUser user = SecurityFrameworkUtils.getLoginUser();
assert user != null; // shouldNotFilter 已经校验 if (user != null) {
// 校验租户是否匹配。 // 如果获取不到租户编号,则尝试使用登陆用户的租户编号
if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) { if (tenantId == null) {
tenantId = user.getTenantId();
TenantContextHolder.setTenantId(tenantId);
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]", log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
user.getTenantId(), user.getId(), user.getUserType(), user.getTenantId(), user.getId(), user.getUserType(),
TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod()); TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
...@@ -39,13 +62,32 @@ public class TenantSecurityWebFilter extends OncePerRequestFilter { ...@@ -39,13 +62,32 @@ public class TenantSecurityWebFilter extends OncePerRequestFilter {
"您无权访问该租户的数据")); "您无权访问该租户的数据"));
return; 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); chain.doFilter(request, response);
} }
@Override private boolean isIgnoreUrl(HttpServletRequest request) {
protected boolean shouldNotFilter(HttpServletRequest request) { // 快速匹配,保证性能
return SecurityFrameworkUtils.getLoginUser() == null; 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;
} }
} }
...@@ -8,15 +8,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -8,15 +8,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo; import springfox.documentation.service.*;
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.spi.DocumentationType; import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket; 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;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Predicate;
import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
...@@ -37,8 +30,8 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka ...@@ -37,8 +30,8 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka
@EnableSwagger2 @EnableSwagger2
@EnableKnife4j @EnableKnife4j
@ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) @ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
// 允许使用 swagger.enable=false 禁用 Swagger // 允许使用 swagger.enable=false 禁用 Swagger
@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
@EnableConfigurationProperties(SwaggerProperties.class) @EnableConfigurationProperties(SwaggerProperties.class)
public class YudaoSwaggerAutoConfiguration { public class YudaoSwaggerAutoConfiguration {
......
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());
}
}
...@@ -39,10 +39,6 @@ ...@@ -39,10 +39,6 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<!-- Web 相关 --> <!-- Web 相关 -->
<dependency> <dependency>
...@@ -67,6 +63,12 @@ ...@@ -67,6 +63,12 @@
<artifactId>yudao-spring-boot-starter-config</artifactId> <artifactId>yudao-spring-boot-starter-config</artifactId>
</dependency> </dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 --> <!-- 消息队列相关 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
......
...@@ -4,7 +4,6 @@ import cn.hutool.core.io.IoUtil; ...@@ -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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 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.FilePageReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO;
import cn.iocoder.yudao.module.infra.convert.file.FileConvert; import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
...@@ -62,7 +61,6 @@ public class FileController { ...@@ -62,7 +61,6 @@ public class FileController {
@ApiOperation("下载文件") @ApiOperation("下载文件")
@ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class) @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class)
public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException { public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
TenantContextHolder.setNullTenantId();
FileDO file = fileService.getFile(path); FileDO file = fileService.getFile(path);
if (file == null) { if (file == null) {
log.warn("[getFile][path({}) 文件不存在]", path); log.warn("[getFile][path({}) 文件不存在]", path);
......
package cn.iocoder.yudao.module.infra.dal.dataobject.file; 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.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
...@@ -21,7 +21,7 @@ import java.io.InputStream; ...@@ -21,7 +21,7 @@ import java.io.InputStream;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class FileDO extends TenantBaseDO { public class FileDO extends BaseDO {
/** /**
* 文件路径 * 文件路径
......
...@@ -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;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
...@@ -21,7 +21,7 @@ import java.util.Date; ...@@ -21,7 +21,7 @@ import java.util.Date;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class ApiAccessLogDO extends TenantBaseDO { public class ApiAccessLogDO extends BaseDO {
/** /**
* 编号 * 编号
......
package cn.iocoder.yudao.module.infra.dal.dataobject.logger; package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 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 cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
...@@ -21,7 +21,7 @@ import java.util.Date; ...@@ -21,7 +21,7 @@ import java.util.Date;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class ApiErrorLogDO extends TenantBaseDO { public class ApiErrorLogDO extends BaseDO {
/** /**
* 编号 * 编号
......
...@@ -54,8 +54,9 @@ public class LoginLogCreateReqDTO { ...@@ -54,8 +54,9 @@ public class LoginLogCreateReqDTO {
private String userIp; private String userIp;
/** /**
* 浏览器 UserAgent * 浏览器 UserAgent
*
* 允许空,原因:Job 过期登出时,是无法传递 UserAgent 的
*/ */
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent; private String userAgent;
} }
...@@ -53,11 +53,11 @@ ...@@ -53,11 +53,11 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> <artifactId>yudao-spring-boot-starter-biz-social</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-social</artifactId> <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency> </dependency>
<!-- Web 相关 --> <!-- Web 相关 -->
...@@ -77,6 +77,12 @@ ...@@ -77,6 +77,12 @@
<artifactId>yudao-spring-boot-starter-redis</artifactId> <artifactId>yudao-spring-boot-starter-redis</artifactId>
</dependency> </dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 --> <!-- 消息队列相关 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
......
package cn.iocoder.yudao.module.system.dal.dataobject.auth; package cn.iocoder.yudao.module.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
...@@ -25,7 +25,7 @@ import java.util.Date; ...@@ -25,7 +25,7 @@ import java.util.Date;
@Data @Data
@Builder @Builder
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class UserSessionDO extends TenantBaseDO { public class UserSessionDO extends BaseDO {
/** /**
* 会话编号, 即 sessionId * 会话编号, 即 sessionId
......
package cn.iocoder.yudao.module.system.dal.dataobject.dept; 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.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.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
...@@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode; ...@@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode;
@TableName("system_dept") @TableName("system_dept")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class DeptDO extends TenantBaseDO { public class DeptDO extends BaseDO {
/** /**
* 部门ID * 部门ID
......
package cn.iocoder.yudao.module.system.dal.dataobject.dept; package cn.iocoder.yudao.module.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
...@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode; ...@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@TableName("system_post") @TableName("system_post")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PostDO extends TenantBaseDO { public class PostDO extends BaseDO {
/** /**
* 岗位序号 * 岗位序号
......
...@@ -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;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
...@@ -22,7 +22,7 @@ import java.util.Map; ...@@ -22,7 +22,7 @@ import java.util.Map;
@TableName(value = "system_operate_log", autoResultMap = true) @TableName(value = "system_operate_log", autoResultMap = true)
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class OperateLogDO extends TenantBaseDO { public class OperateLogDO extends BaseDO {
/** /**
* {@link #javaMethodArgs} 的最大长度 * {@link #javaMethodArgs} 的最大长度
......
package cn.iocoder.yudao.module.system.dal.dataobject.notice; 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.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.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
...@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode; ...@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
@TableName("system_notice") @TableName("system_notice")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class NoticeDO extends TenantBaseDO { public class NoticeDO extends BaseDO {
/** /**
* 公告ID * 公告ID
......
package cn.iocoder.yudao.module.system.dal.dataobject.user; 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.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 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.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
......
...@@ -19,12 +19,12 @@ import javax.annotation.Resource; ...@@ -19,12 +19,12 @@ import javax.annotation.Resource;
public class UserSessionTimeoutJob implements JobHandler { public class UserSessionTimeoutJob implements JobHandler {
@Resource @Resource
private UserSessionService sysUserSessionService; private UserSessionService userSessionService;
@Override @Override
public String execute(String param) throws Exception { public String execute(String param) throws Exception {
// 执行过期 // 执行过期
Long timeoutCount = sysUserSessionService.clearSessionTimeout(); Long timeoutCount = userSessionService.clearSessionTimeout();
// 返回结果,记录每次的超时数量 // 返回结果,记录每次的超时数量
return String.format("移除在线会话数量为 %s 个", timeoutCount); return String.format("移除在线会话数量为 %s 个", timeoutCount);
} }
......
...@@ -146,7 +146,7 @@ public class PermissionServiceImpl implements PermissionService { ...@@ -146,7 +146,7 @@ public class PermissionServiceImpl implements PermissionService {
public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,
Collection<Integer> menusStatuses) { Collection<Integer> menusStatuses) {
// 任一一个参数为空时,不返回任何菜单 // 任一一个参数为空时,不返回任何菜单
if (CollectionUtils.isAnyEmpty(roleIds, menusStatuses, menusStatuses)) { if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) {
return Collections.emptyList(); return Collections.emptyList();
} }
// 判断角色是否包含管理员 // 判断角色是否包含管理员
......
...@@ -38,10 +38,6 @@ ...@@ -38,10 +38,6 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId> <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<!-- Web 相关 --> <!-- Web 相关 -->
<dependency> <dependency>
......
...@@ -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;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil; 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.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO; import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO; import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
...@@ -60,7 +60,7 @@ public class CodegenBuilder { ...@@ -60,7 +60,7 @@ public class CodegenBuilder {
*/ */
public static final String TENANT_ID_FIELD = "tenant_id"; 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<>(); public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
/** /**
...@@ -96,7 +96,8 @@ public class CodegenBuilder { ...@@ -96,7 +96,8 @@ public class CodegenBuilder {
.build(); .build();
static { 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 相关的字段 // 处理 OPERATION 相关的字段
CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
......
package cn.iocoder.yudao.module.tool.service.codegen.inner; 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.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.TemplateConfig; import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine; 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;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 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 cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 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.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 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.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 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.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO; import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.tool.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -115,7 +111,8 @@ public class CodegenEngine { ...@@ -115,7 +111,8 @@ public class CodegenEngine {
private void initGlobalBindingMap() { private void initGlobalBindingMap() {
// 全局配置 // 全局配置
globalBindingMap.put("basePackage", codegenProperties.getBasePackage()); globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage() + '.' + "framework"); // 用于后续获取测试类的 package 地址 globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage()
+ '.' + "framework"); // 用于后续获取测试类的 package 地址
// 全局 Java Bean // 全局 Java Bean
globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); globalBindingMap.put("CommonResultClassName", CommonResult.class.getName());
globalBindingMap.put("PageResultClassName", PageResult.class.getName()); globalBindingMap.put("PageResultClassName", PageResult.class.getName());
...@@ -123,6 +120,7 @@ public class CodegenEngine { ...@@ -123,6 +120,7 @@ public class CodegenEngine {
globalBindingMap.put("PageParamClassName", PageParam.class.getName()); globalBindingMap.put("PageParamClassName", PageParam.class.getName());
globalBindingMap.put("DictFormatClassName", DictFormat.class.getName()); globalBindingMap.put("DictFormatClassName", DictFormat.class.getName());
// DO 类,独有字段 // DO 类,独有字段
globalBindingMap.put("BaseDOClassName", BaseDO.class.getName());
globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS); globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS);
globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName()); globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName());
globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName()); globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName());
...@@ -156,15 +154,6 @@ public class CodegenEngine { ...@@ -156,15 +154,6 @@ public class CodegenEngine {
// permission 前缀 // permission 前缀
bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase); 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()); // 有序 final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序
TEMPLATES.forEach((vmPath, filePath) -> { TEMPLATES.forEach((vmPath, filePath) -> {
......
...@@ -17,7 +17,7 @@ import ${BaseDOClassName}; ...@@ -17,7 +17,7 @@ import ${BaseDOClassName};
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class ${table.className}DO extends ${BaseDOClassName_simple} { public class ${table.className}DO extends BaseDO {
#foreach ($column in $columns) #foreach ($column in $columns)
#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
......
...@@ -78,7 +78,9 @@ yudao: ...@@ -78,7 +78,9 @@ yudao:
- cn.iocoder.yudao.module.system.enums.ErrorCodeConstants - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants
tenant: # 多租户相关配置项 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: # 短信验证码相关的配置项 sms-code: # 短信验证码相关的配置项
expire-times: 10m expire-times: 10m
send-frequency: 1m send-frequency: 1m
......
...@@ -10,3 +10,6 @@ VUE_APP_BASE_API = '/dev-api' ...@@ -10,3 +10,6 @@ VUE_APP_BASE_API = '/dev-api'
# 路由懒加载 # 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true VUE_CLI_BABEL_TRANSPILE_MODULES = true
# 多租户的开关
VUE_APP_TENANT_ENABLE = true
...@@ -4,6 +4,7 @@ import store from '@/store' ...@@ -4,6 +4,7 @@ import store from '@/store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode' import errorCode from '@/utils/errorCode'
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import {getTenantEnable} from "@/utils/ruoyi";
// 是否显示重新登录 // 是否显示重新登录
let isReloginShow; let isReloginShow;
...@@ -24,10 +25,12 @@ service.interceptors.request.use(config => { ...@@ -24,10 +25,12 @@ service.interceptors.request.use(config => {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
} }
// 设置租户 // 设置租户
if (getTenantEnable()) {
const tenantId = Cookies.get('tenantId'); const tenantId = Cookies.get('tenantId');
if (tenantId) { if (tenantId) {
config.headers['tenant-id'] = tenantId; config.headers['tenant-id'] = tenantId;
} }
}
// get请求映射params参数 // get请求映射params参数
if (config.method === 'get' && config.params) { if (config.method === 'get' && config.params) {
let url = config.url + '?'; let url = config.url + '?';
......
...@@ -170,3 +170,17 @@ export function getNowDateTime(timeStr) { ...@@ -170,3 +170,17 @@ export function getNowDateTime(timeStr) {
let seconds = now.getSeconds().toString().padStart(2, "0") // 得到秒; let seconds = now.getSeconds().toString().padStart(2, "0") // 得到秒;
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; 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;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="login"> <div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">芋道后台管理系统</h3> <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='租户'> <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" /> <svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon" />
</el-input> </el-input>
...@@ -54,7 +54,8 @@ import { getCodeImg,socialAuthRedirect } from "@/api/login"; ...@@ -54,7 +54,8 @@ import { getCodeImg,socialAuthRedirect } from "@/api/login";
import { getTenantIdByName } from "@/api/system/tenant"; import { getTenantIdByName } from "@/api/system/tenant";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt' import { encrypt, decrypt } from '@/utils/jsencrypt'
import {InfraApiErrorLogProcessStatusEnum, SystemUserSocialTypeEnum} from "@/utils/constants"; import {SystemUserSocialTypeEnum} from "@/utils/constants";
import { getTenantEnable } from "@/utils/ruoyi";
export default { export default {
name: "Login", name: "Login",
...@@ -62,6 +63,7 @@ export default { ...@@ -62,6 +63,7 @@ export default {
return { return {
codeUrl: "", codeUrl: "",
captchaEnable: true, captchaEnable: true,
tenantEnable: true,
loginForm: { loginForm: {
username: "admin", username: "admin",
password: "admin123", password: "admin123",
...@@ -71,6 +73,13 @@ export default { ...@@ -71,6 +73,13 @@ export default {
tenantName: "芋道源码", tenantName: "芋道源码",
}, },
loginRules: { loginRules: {
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
password: [
{ required: true, trigger: "blur", message: "密码不能为空" }
],
code: [{ required: true, trigger: "change", message: "验证码不能为空" }],
tenantName: [ tenantName: [
{ required: true, trigger: "blur", message: "租户不能为空" }, { required: true, trigger: "blur", message: "租户不能为空" },
{ {
...@@ -90,13 +99,6 @@ export default { ...@@ -90,13 +99,6 @@ export default {
trigger: 'blur' trigger: 'blur'
} }
], ],
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
password: [
{ required: true, trigger: "blur", message: "密码不能为空" }
],
code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
}, },
loading: false, loading: false,
redirect: undefined, redirect: undefined,
...@@ -113,6 +115,8 @@ export default { ...@@ -113,6 +115,8 @@ export default {
// } // }
// }, // },
created() { created() {
// 租户开关
this.tenantEnable = getTenantEnable();
// 重定向地址 // 重定向地址
this.redirect = this.$route.query.redirect; this.redirect = this.$route.query.redirect;
this.getCode(); this.getCode();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册