init
This commit is contained in:
@@ -80,5 +80,9 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -25,10 +25,9 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
public class ThreadPoolConfig {
|
||||
|
||||
/**
|
||||
* 核心线程数 = cpu 核心数 + 1
|
||||
* 核心线程数 = cpu 核心数 + 1 TODO 线程池
|
||||
*/
|
||||
// private final int core = Runtime.getRuntime().availableProcessors() + 1;
|
||||
private final int core = 6 + 1;
|
||||
private final int core = Runtime.getRuntime().availableProcessors() + 1;
|
||||
|
||||
|
||||
@Bean(name = "threadPoolTaskExecutor")
|
||||
|
||||
@@ -12,38 +12,4 @@ public interface CacheConstants {
|
||||
*/
|
||||
String ONLINE_TOKEN_KEY = "online_tokens:";
|
||||
|
||||
/**
|
||||
* 单天在线APP用户
|
||||
*/
|
||||
String ONLINE_TODAY_TOKEN_KEY = "online_tokens_today:%s";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
String CAPTCHA_CODE_KEY = "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
String SYS_CONFIG_KEY = "sys_config:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
String SYS_DICT_KEY = "sys_dict:";
|
||||
|
||||
/**
|
||||
* 防重提交 redis key
|
||||
*/
|
||||
String REPEAT_SUBMIT_KEY = "repeat_submit:";
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
String RATE_LIMIT_KEY = "rate_limit:";
|
||||
|
||||
/**
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
||||
}
|
||||
|
||||
@@ -15,20 +15,15 @@ package com.ruoyi.component.core.constant;
|
||||
*/
|
||||
public interface CacheNames {
|
||||
|
||||
/**
|
||||
* 演示案例
|
||||
*/
|
||||
String DEMO_CACHE = "demo:cache#60s#10m#20";
|
||||
|
||||
/**
|
||||
* 系统配置
|
||||
*/
|
||||
String SYS_CONFIG = "sys_config";
|
||||
String SYS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_config";
|
||||
|
||||
/**
|
||||
* 数据字典
|
||||
*/
|
||||
String SYS_DICT = "sys_dict";
|
||||
String SYS_DICT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_dict";
|
||||
|
||||
/**
|
||||
* 用户账户
|
||||
@@ -52,9 +47,4 @@ public interface CacheNames {
|
||||
*/
|
||||
String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
|
||||
|
||||
/**
|
||||
* 在线用户
|
||||
*/
|
||||
String ONLINE_TOKEN = "online_tokens";
|
||||
|
||||
}
|
||||
|
||||
@@ -36,4 +36,14 @@ public interface GlobalConstants {
|
||||
* 三方认证 redis key
|
||||
*/
|
||||
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
String SYS_DICT_KEY = GLOBAL_REDIS_KEY + "sys_dict:";
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
String SYS_CONFIG_KEY = GLOBAL_REDIS_KEY + "sys_config:";
|
||||
}
|
||||
|
||||
@@ -139,9 +139,4 @@ public interface UserConstants {
|
||||
*/
|
||||
Long ADMIN_ID = 1L;
|
||||
|
||||
/**
|
||||
* 管理员角色key
|
||||
*/
|
||||
String ADMIN_ROLE_KEY = "admin";
|
||||
|
||||
}
|
||||
|
||||
@@ -100,6 +100,8 @@ public class LoginUser implements Serializable {
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 获取登录id
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruoyi.component.core.executor;
|
||||
|
||||
import com.alibaba.ttl.threadpool.TtlExecutors;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class ExecutorConstant {
|
||||
|
||||
private final static int CPU_NUM = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
public static Executor COMMON_EXECUTOR;
|
||||
|
||||
static {
|
||||
ThreadPoolExecutor commonExecutor = new ThreadPoolExecutor(CPU_NUM,
|
||||
CPU_NUM << 2,
|
||||
5,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(50),
|
||||
init("commonThreadPool-%d"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
COMMON_EXECUTOR = TtlExecutors.getTtlExecutor(commonExecutor);
|
||||
}
|
||||
|
||||
private static ThreadFactory init(String nameFormat){
|
||||
return new ThreadFactoryBuilder().setNameFormat(nameFormat).build();
|
||||
}
|
||||
|
||||
private static ThreadPoolExecutor initExecutor(int corePoolSize, int maxPoolSize, int keepAliveTime, TimeUnit timeUnit,
|
||||
BlockingQueue<Runnable> workQueue, String nameFormat){
|
||||
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue,
|
||||
init(nameFormat));
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isMySql()">
|
||||
select column_name,
|
||||
(case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required,
|
||||
(case when column_key = 'PRI' then '1' else '0' end) as is_pk,
|
||||
@@ -41,7 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
|
||||
order by ordinal_position
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isOracle()">
|
||||
select lower(temp.column_name) as column_name,
|
||||
(case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else '0' end) as is_required,
|
||||
(case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
|
||||
@@ -61,7 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
WHERE temp.row_flg = 1
|
||||
ORDER BY temp.column_id
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isPostgerSql()">
|
||||
SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type
|
||||
FROM (
|
||||
SELECT c.relname AS table_name,
|
||||
@@ -95,7 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
WHERE table_name = (#{tableName})
|
||||
AND column_type <![CDATA[ <> ]]> '-'
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isSqlServer()">
|
||||
SELECT
|
||||
cast(A.NAME as nvarchar) as column_name,
|
||||
cast(B.NAME as nvarchar) + (case when B.NAME = 'numeric' then '(' + cast(A.prec as nvarchar) + ',' + cast(A.scale as nvarchar) + ')' else '' end) as column_type,
|
||||
|
||||
@@ -54,7 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<select id="selectPageDbTableList" resultMap="GenTableResult">
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isMySql()">
|
||||
select table_name, table_comment, create_time, update_time
|
||||
from information_schema.tables
|
||||
where table_schema = (select database())
|
||||
@@ -68,7 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</if>
|
||||
order by create_time desc
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isOracle()">
|
||||
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
|
||||
from user_tables dt, user_tab_comments dtc, user_objects uo
|
||||
where dt.table_name = dtc.table_name
|
||||
@@ -84,7 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</if>
|
||||
order by create_time desc
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isPostgerSql()">
|
||||
select table_name, table_comment, create_time, update_time
|
||||
from (
|
||||
SELECT c.relname AS table_name,
|
||||
@@ -108,7 +108,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</if>
|
||||
order by create_time desc
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isSqlServer()">
|
||||
SELECT cast(D.NAME as nvarchar) as table_name,
|
||||
cast(F.VALUE as nvarchar) as table_comment,
|
||||
crdate as create_time,
|
||||
@@ -129,7 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectDbTableListByNames" resultMap="GenTableResult">
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isMySql()">
|
||||
select table_name, table_comment, create_time, update_time from information_schema.tables
|
||||
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
|
||||
and table_name in
|
||||
@@ -137,7 +137,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
#{name}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isOracle()">
|
||||
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
|
||||
from user_tables dt, user_tab_comments dtc, user_objects uo
|
||||
where dt.table_name = dtc.table_name
|
||||
@@ -150,7 +150,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
#{name}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isPostgerSql()">
|
||||
select table_name, table_comment, create_time, update_time
|
||||
from (
|
||||
SELECT c.relname AS table_name,
|
||||
@@ -170,7 +170,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
#{name}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isSqlServer()">
|
||||
SELECT cast(D.NAME as nvarchar) as table_name,
|
||||
cast(F.VALUE as nvarchar) as table_comment,
|
||||
crdate as create_time,
|
||||
@@ -187,12 +187,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isMySql()">
|
||||
select table_name, table_comment, create_time, update_time from information_schema.tables
|
||||
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
|
||||
and table_name = #{tableName}
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isOracle()">
|
||||
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
|
||||
from user_tables dt, user_tab_comments dtc, user_objects uo
|
||||
where dt.table_name = dtc.table_name
|
||||
@@ -202,7 +202,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND dt.table_name NOT IN (select table_name from gen_table)
|
||||
and lower(dt.table_name) = #{tableName}
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isPostgerSql()">
|
||||
select table_name, table_comment, create_time, update_time
|
||||
from (
|
||||
SELECT c.relname AS table_name,
|
||||
@@ -219,7 +219,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
|
||||
and table_name = #{tableName}
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
|
||||
<if test="@com.ruoyi.component.mybatis.helper.DataBaseHelper@isSqlServer()">
|
||||
SELECT cast(D.NAME as nvarchar) as table_name,
|
||||
cast(F.VALUE as nvarchar) as table_comment,
|
||||
crdate as create_time,
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.ruoyi.component.core.constant.CacheConstants;
|
||||
import com.ruoyi.component.core.constant.GlobalConstants;
|
||||
import com.ruoyi.component.core.domain.R;
|
||||
import com.ruoyi.component.core.exception.ServiceException;
|
||||
import com.ruoyi.component.core.util.MessageUtils;
|
||||
@@ -57,7 +58,7 @@ public class RepeatSubmitAspect {
|
||||
|
||||
submitKey = SecureUtil.md5(submitKey + ":" + nowParams);
|
||||
// 唯一标识(指定key + url + 消息头)
|
||||
String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
|
||||
String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey;
|
||||
if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) {
|
||||
KEY_CACHE.set(cacheRepeatKey);
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.ruoyi.component.oss.constant;
|
||||
|
||||
import com.ruoyi.component.core.constant.GlobalConstants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -13,7 +15,7 @@ public interface OssConstant {
|
||||
/**
|
||||
* 默认配置KEY
|
||||
*/
|
||||
String DEFAULT_CONFIG_KEY = "sys_oss:default_config";
|
||||
String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config";
|
||||
|
||||
/**
|
||||
* 预览列表资源开关Key
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.ruoyi.component.ratelimiter.aspectj;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.ruoyi.component.core.constant.CacheConstants;
|
||||
import com.ruoyi.component.core.constant.GlobalConstants;
|
||||
import com.ruoyi.component.core.exception.ServiceException;
|
||||
import com.ruoyi.component.core.util.MessageUtils;
|
||||
import com.ruoyi.component.core.util.ServletUtils;
|
||||
@@ -113,7 +114,7 @@ public class RateLimiterAspect {
|
||||
throw new ServiceException("限流key解析异常!请联系管理员!");
|
||||
}
|
||||
}
|
||||
StringBuilder stringBuffer = new StringBuilder(CacheConstants.RATE_LIMIT_KEY);
|
||||
StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY);
|
||||
stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":");
|
||||
if (rateLimiter.limitType() == LimitType.IP) {
|
||||
// 获取请求ip
|
||||
|
||||
@@ -35,9 +35,11 @@ public class LoginHelper {
|
||||
|
||||
public static final String LOGIN_USER_KEY = "loginUser";
|
||||
public static final String USER_KEY = "userId";
|
||||
|
||||
public static final String TENANT_KEY = "tenantId";
|
||||
|
||||
public static String getTenantIdByToken(String token) {
|
||||
return Convert.toStr(StpUtil.getExtra(token,TENANT_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取租户ID
|
||||
@@ -83,6 +85,7 @@ public class LoginHelper {
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
storage.set(LOGIN_USER_KEY, loginUser);
|
||||
storage.set(USER_KEY, loginUser.getUserId());
|
||||
storage.set(TENANT_KEY, loginUser.getTenantId());
|
||||
SaLoginModel model = new SaLoginModel();
|
||||
if (ObjectUtil.isNotNull(deviceType)) {
|
||||
model.setDevice(deviceType.getDevice());
|
||||
@@ -95,7 +98,9 @@ public class LoginHelper {
|
||||
// } else if (userType == UserType.APP_USER) {
|
||||
// model.setTimeout(86400).setActiveTimeout(1800);
|
||||
// }
|
||||
StpUtil.login(loginUser.getLoginId(), model.setExtra(USER_KEY, loginUser.getUserId()));
|
||||
model.setExtra(USER_KEY, loginUser.getUserId());
|
||||
model.setExtra(TENANT_KEY,loginUser.getTenantId());
|
||||
StpUtil.login(loginUser.getLoginId(), model);
|
||||
StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.ruoyi.component.core.util.ServletUtils;
|
||||
import com.ruoyi.component.core.util.spring.SpringUtils;
|
||||
import com.ruoyi.component.satoken.utils.LoginHelper;
|
||||
import com.ruoyi.component.security.config.properties.SecurityProperties;
|
||||
import com.ruoyi.component.security.handler.AllUrlHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -44,24 +46,6 @@ public class SecurityConfig implements WebMvcConfigurer {
|
||||
.check(() -> {
|
||||
// 检查是否登录 是否有token
|
||||
StpUtil.checkLogin();
|
||||
|
||||
// 检查 header 与 param 里的 clientid 与 token 里的是否一致 TODO
|
||||
// String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
|
||||
// String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
|
||||
// String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
|
||||
// if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
|
||||
// // token 无效
|
||||
// throw NotLoginException.newInstance(StpUtil.getLoginType(),
|
||||
// "-100", "客户端ID与Token不匹配",
|
||||
// StpUtil.getTokenValue());
|
||||
// }
|
||||
|
||||
// 有效率影响 用于临时测试
|
||||
// if (log.isDebugEnabled()) {
|
||||
// log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());
|
||||
// log.info("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
|
||||
// }
|
||||
|
||||
});
|
||||
})).addPathPatterns("/**")
|
||||
// 排除不需要拦截的路径
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.ruoyi.component.mybatis.config.MybatisPlusConfig;
|
||||
import com.ruoyi.component.redis.config.RedisConfig;
|
||||
import com.ruoyi.component.redis.properties.RedissonProperties;
|
||||
import com.ruoyi.component.tenant.core.TenantSaTokenDao;
|
||||
import com.ruoyi.component.tenant.filter.TenantFilter;
|
||||
import com.ruoyi.component.tenant.handle.PlusTenantLineHandler;
|
||||
import com.ruoyi.component.tenant.handle.TenantKeyPrefixHandler;
|
||||
import com.ruoyi.component.tenant.manager.TenantSpringCacheManager;
|
||||
@@ -20,6 +21,7 @@ import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
@@ -88,6 +90,17 @@ public class TenantConfig {
|
||||
return new TenantSpringCacheManager();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Bean
|
||||
public FilterRegistrationBean tenantFilter() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(new TenantFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("tenantFilter");
|
||||
registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
|
||||
return registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多租户鉴权dao实现
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.ruoyi.component.tenant.filter;
|
||||
|
||||
|
||||
import cn.hutool.json.JSON;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ruoyi.component.core.constant.TenantConstants;
|
||||
import com.ruoyi.component.core.domain.R;
|
||||
import com.ruoyi.component.core.util.ServletUtils;
|
||||
import com.ruoyi.component.core.util.StringUtils;
|
||||
import com.ruoyi.component.satoken.utils.LoginHelper;
|
||||
import com.ruoyi.component.tenant.helper.TenantHelper;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class TenantFilter implements Filter {
|
||||
public static final String TENANT_ID_HEADER = "Tenant-ID";
|
||||
|
||||
private static final Set<String> IGNORE_URL = new HashSet<>();
|
||||
static {
|
||||
IGNORE_URL.add("/login");
|
||||
IGNORE_URL.add("/captchaImage");
|
||||
}
|
||||
private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
if(!(servletRequest instanceof HttpServletRequest)){
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
try {
|
||||
String requestURI = request.getRequestURI();
|
||||
for (String ignoreUrlMatch : IGNORE_URL) {
|
||||
boolean match = ANT_PATH_MATCHER.match(ignoreUrlMatch, requestURI);
|
||||
if(match){
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
String tenantHeader = request.getHeader(TENANT_ID_HEADER);
|
||||
boolean login = TenantHelper.isLogin();
|
||||
if(login){
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if(TenantConstants.SUPER_ADMIN_ID.equals(userId)){
|
||||
TenantHelper.setTenantId(tenantHeader);
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!StringUtils.isBlank(tenantHeader)){
|
||||
if(login){
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
if(tenantId == null || !tenantId.equals(tenantHeader)){
|
||||
ServletUtils.renderString(response, JSONUtil.toJsonStr(R.fail("平台错误")));
|
||||
return;
|
||||
}
|
||||
TenantHelper.setTenantId(tenantId);
|
||||
}else{
|
||||
TenantHelper.setTenantId(tenantHeader);
|
||||
}
|
||||
} else {
|
||||
if(login){
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
if(tenantId == null){
|
||||
ServletUtils.renderString(response, JSONUtil.toJsonStr(R.fail("平台错误")));
|
||||
return;
|
||||
}
|
||||
TenantHelper.setTenantId(tenantId);
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} finally {
|
||||
TenantHelper.clearTenant();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.ruoyi.component.tenant.handle;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import com.ruoyi.component.core.exception.ServiceException;
|
||||
import com.ruoyi.component.core.util.StringUtils;
|
||||
import com.ruoyi.component.tenant.helper.TenantHelper;
|
||||
import com.ruoyi.component.tenant.properties.TenantProperties;
|
||||
@@ -29,7 +30,8 @@ public class PlusTenantLineHandler implements TenantLineHandler {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
log.error("无法获取有效的租户id -> Null");
|
||||
return new NullValue();
|
||||
throw new ServiceException("无法获取有效的平台");
|
||||
// return new NullValue();
|
||||
}
|
||||
// 返回固定租户
|
||||
return new StringValue(tenantId);
|
||||
@@ -37,20 +39,15 @@ public class PlusTenantLineHandler implements TenantLineHandler {
|
||||
|
||||
@Override
|
||||
public boolean ignoreTable(String tableName) {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
// 判断是否有租户
|
||||
if (StringUtils.isNotBlank(tenantId)) {
|
||||
// 不需要过滤租户的表
|
||||
List<String> excludes = tenantProperties.getExcludes();
|
||||
// 非业务表
|
||||
List<String> tables = ListUtil.toList(
|
||||
"gen_table",
|
||||
"gen_table_column"
|
||||
);
|
||||
tables.addAll(excludes);
|
||||
return tables.contains(tableName);
|
||||
}
|
||||
return true;
|
||||
// 不需要过滤租户的表
|
||||
List<String> excludes = tenantProperties.getExcludes();
|
||||
// 非业务表
|
||||
List<String> tables = ListUtil.toList(
|
||||
"gen_table",
|
||||
"gen_table_column"
|
||||
);
|
||||
tables.addAll(excludes);
|
||||
return tables.contains(tableName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ruoyi.component.tenant.handle;
|
||||
|
||||
import com.ruoyi.component.core.constant.GlobalConstants;
|
||||
import com.ruoyi.component.core.exception.ServiceException;
|
||||
import com.ruoyi.component.core.util.StringUtils;
|
||||
import com.ruoyi.component.redis.handler.KeyPrefixHandler;
|
||||
import com.ruoyi.component.tenant.helper.TenantHelper;
|
||||
@@ -32,6 +33,7 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
log.error("无法获取有效的租户id -> Null");
|
||||
throw new ServiceException("无法获取有效的平台");
|
||||
}
|
||||
if (StringUtils.startsWith(name, tenantId + "")) {
|
||||
// 如果存在则直接返回
|
||||
@@ -55,6 +57,7 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
log.error("无法获取有效的租户id -> Null");
|
||||
throw new ServiceException("无法获取有效的平台");
|
||||
}
|
||||
if (StringUtils.startsWith(unmap, tenantId + "")) {
|
||||
// 如果存在则删除
|
||||
|
||||
@@ -6,11 +6,10 @@ import cn.hutool.core.convert.Convert;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
|
||||
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
||||
import com.ruoyi.component.satoken.utils.LoginHelper;
|
||||
import com.ruoyi.component.core.constant.GlobalConstants;
|
||||
import com.ruoyi.component.core.util.StringUtils;
|
||||
import com.ruoyi.component.core.util.spring.SpringUtils;
|
||||
import com.ruoyi.component.redis.util.RedisUtils;
|
||||
import com.ruoyi.component.satoken.utils.LoginHelper;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -26,10 +25,7 @@ import java.util.function.Supplier;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TenantHelper {
|
||||
|
||||
private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
|
||||
|
||||
private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>();
|
||||
|
||||
private static final ThreadLocal<String> DYNAMIC_TENANT = new TransmittableThreadLocal<>();
|
||||
/**
|
||||
* 租户功能是否启用
|
||||
*/
|
||||
@@ -79,22 +75,11 @@ public class TenantHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置动态租户(一直有效 需要手动清理)
|
||||
* <p>
|
||||
* 如果为未登录状态下 那么只在当前线程内生效
|
||||
*/
|
||||
public static void setDynamic(String tenantId) {
|
||||
public static void setTenantId(String tenantId) {
|
||||
if (!isEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!isLogin()) {
|
||||
TEMP_DYNAMIC_TENANT.set(tenantId);
|
||||
return;
|
||||
}
|
||||
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
|
||||
RedisUtils.setCacheObject(cacheKey, tenantId);
|
||||
SaHolder.getStorage().set(cacheKey, tenantId);
|
||||
DYNAMIC_TENANT.set(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,37 +87,21 @@ public class TenantHelper {
|
||||
* <p>
|
||||
* 如果为未登录状态下 那么只在当前线程内生效
|
||||
*/
|
||||
public static String getDynamic() {
|
||||
public static String getTenantId() {
|
||||
if (!isEnable()) {
|
||||
return null;
|
||||
}
|
||||
if (!isLogin()) {
|
||||
return TEMP_DYNAMIC_TENANT.get();
|
||||
}
|
||||
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
|
||||
String tenantId = (String) SaHolder.getStorage().get(cacheKey);
|
||||
if (StringUtils.isNotBlank(tenantId)) {
|
||||
return tenantId;
|
||||
}
|
||||
tenantId = RedisUtils.getCacheObject(cacheKey);
|
||||
SaHolder.getStorage().set(cacheKey, tenantId);
|
||||
return tenantId;
|
||||
return DYNAMIC_TENANT.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除动态租户
|
||||
*/
|
||||
public static void clearDynamic() {
|
||||
public static void clearTenant() {
|
||||
if (!isEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!isLogin()) {
|
||||
TEMP_DYNAMIC_TENANT.remove();
|
||||
return;
|
||||
}
|
||||
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
|
||||
RedisUtils.deleteObject(cacheKey);
|
||||
SaHolder.getStorage().delete(cacheKey);
|
||||
DYNAMIC_TENANT.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,11 +110,11 @@ public class TenantHelper {
|
||||
* @param handle 处理执行方法
|
||||
*/
|
||||
public static void dynamic(String tenantId, Runnable handle) {
|
||||
setDynamic(tenantId);
|
||||
setTenantId(tenantId);
|
||||
try {
|
||||
handle.run();
|
||||
} finally {
|
||||
clearDynamic();
|
||||
clearTenant();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,29 +124,15 @@ public class TenantHelper {
|
||||
* @param handle 处理执行方法
|
||||
*/
|
||||
public static <T> T dynamic(String tenantId, Supplier<T> handle) {
|
||||
setDynamic(tenantId);
|
||||
setTenantId(tenantId);
|
||||
try {
|
||||
return handle.get();
|
||||
} finally {
|
||||
clearDynamic();
|
||||
clearTenant();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前租户id(动态租户优先)
|
||||
*/
|
||||
public static String getTenantId() {
|
||||
if (!isEnable()) {
|
||||
return null;
|
||||
}
|
||||
String tenantId = TenantHelper.getDynamic();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
tenantId = LoginHelper.getTenantId();
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
private static boolean isLogin() {
|
||||
public static boolean isLogin() {
|
||||
try {
|
||||
StpUtil.checkLogin();
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user