forked from github/dataease
Merge pull request #4784 from dataease/pr@dev@perf_multi_login_cache
perf(登录): 多端登录限制缓存优化
This commit is contained in:
commit
5244c65095
@ -9,11 +9,9 @@ import com.auth0.jwt.interfaces.Verification;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import io.dataease.auth.entity.TokenInfo;
|
import io.dataease.auth.entity.TokenInfo;
|
||||||
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
|
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
|
||||||
import io.dataease.commons.exception.DEException;
|
|
||||||
import io.dataease.commons.model.OnlineUserModel;
|
import io.dataease.commons.model.OnlineUserModel;
|
||||||
import io.dataease.commons.utils.*;
|
import io.dataease.commons.utils.*;
|
||||||
import io.dataease.exception.DataEaseException;
|
import io.dataease.exception.DataEaseException;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
@ -23,7 +21,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class JWTUtils {
|
public class JWTUtils {
|
||||||
|
|
||||||
@ -96,13 +93,9 @@ public class JWTUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<OnlineUserModel> filterValid(Set<OnlineUserModel> userModels) {
|
private static String models2Json(OnlineUserModel model, boolean withCurToken, String token) {
|
||||||
Set<OnlineUserModel> models = userModels.stream().filter(JWTUtils::tokenValid).collect(Collectors.toSet());
|
Set<OnlineUserModel> models = new LinkedHashSet<>();
|
||||||
|
models.add(model);
|
||||||
return models;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String models2Json(Set<OnlineUserModel> models, boolean withCurToken, String token) {
|
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
List<OnlineUserModel> userModels = models.stream().map(item -> {
|
List<OnlineUserModel> userModels = models.stream().map(item -> {
|
||||||
item.setToken(null);
|
item.setToken(null);
|
||||||
@ -120,31 +113,25 @@ public class JWTUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String seizeSign(Long userId, String token) {
|
public static String seizeSign(Long userId, String token) {
|
||||||
Set<OnlineUserModel> userModels = Optional.ofNullable(TokenCacheUtils.onlineUserTokens(userId)).orElse(new LinkedHashSet<>());
|
Optional.ofNullable(TokenCacheUtils.onlineUserToken(userId)).ifPresent(model -> TokenCacheUtils.add(model.getToken(), userId));
|
||||||
userModels.stream().forEach(model -> {
|
TokenCacheUtils.add2OnlinePools(token, userId);
|
||||||
TokenCacheUtils.add(model.getToken(), userId);
|
|
||||||
});
|
|
||||||
userModels.clear();
|
|
||||||
OnlineUserModel curModel = TokenCacheUtils.buildModel(token);
|
|
||||||
userModels.add(curModel);
|
|
||||||
TokenCacheUtils.resetOnlinePools(userId, userModels);
|
|
||||||
return IPUtils.get();
|
return IPUtils.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String sign(TokenInfo tokenInfo, String secret, boolean writeOnline) {
|
public static String sign(TokenInfo tokenInfo, String secret, boolean writeOnline) {
|
||||||
|
|
||||||
Long userId = tokenInfo.getUserId();
|
Long userId = tokenInfo.getUserId();
|
||||||
String multiLoginType = null;
|
String multiLoginType = null;
|
||||||
if (writeOnline && StringUtils.equals("1", (multiLoginType = TokenCacheUtils.multiLoginType()))) {
|
if (writeOnline && StringUtils.equals("1", (multiLoginType = TokenCacheUtils.multiLoginType()))) {
|
||||||
Set<OnlineUserModel> userModels = TokenCacheUtils.onlineUserTokens(userId);
|
OnlineUserModel userModel = TokenCacheUtils.onlineUserToken(userId);
|
||||||
if (CollectionUtils.isNotEmpty(userModels) && CollectionUtils.isNotEmpty((userModels = filterValid(userModels)))) {
|
if (ObjectUtils.isNotEmpty(userModel) && tokenValid(userModel)) {
|
||||||
TokenCacheUtils.resetOnlinePools(userId, userModels);
|
|
||||||
HttpServletResponse response = ServletUtils.response();
|
HttpServletResponse response = ServletUtils.response();
|
||||||
Cookie cookie_token = new Cookie("MultiLoginError1", models2Json(userModels, false, null));cookie_token.setPath("/");
|
Cookie cookie_token = new Cookie("MultiLoginError1", models2Json(userModel, false, null));
|
||||||
|
cookie_token.setPath("/");
|
||||||
cookie_token.setPath("/");
|
cookie_token.setPath("/");
|
||||||
response.addCookie(cookie_token);
|
response.addCookie(cookie_token);
|
||||||
DataEaseException.throwException("MultiLoginError1");
|
DataEaseException.throwException("MultiLoginError1");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (ObjectUtils.isEmpty(expireTime)) {
|
if (ObjectUtils.isEmpty(expireTime)) {
|
||||||
expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L);
|
expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L);
|
||||||
@ -156,23 +143,21 @@ public class JWTUtils {
|
|||||||
.withClaim("username", tokenInfo.getUsername())
|
.withClaim("username", tokenInfo.getUsername())
|
||||||
.withClaim("userId", userId);
|
.withClaim("userId", userId);
|
||||||
String sign = builder.withExpiresAt(date).sign(algorithm);
|
String sign = builder.withExpiresAt(date).sign(algorithm);
|
||||||
if (writeOnline && !StringUtils.equals("0", multiLoginType)) {
|
|
||||||
if (StringUtils.equals("2", multiLoginType)) {
|
if (StringUtils.equals("2", multiLoginType)) {
|
||||||
Set<OnlineUserModel> userModels = TokenCacheUtils.onlineUserTokens(userId);
|
OnlineUserModel userModel = TokenCacheUtils.onlineUserToken(userId);
|
||||||
if (CollectionUtils.isNotEmpty(userModels) && CollectionUtils.isNotEmpty((userModels = filterValid(userModels)))) {
|
if (ObjectUtils.isNotEmpty(userModel) && tokenValid(userModel)) {
|
||||||
HttpServletResponse response = ServletUtils.response();
|
HttpServletResponse response = ServletUtils.response();
|
||||||
Cookie cookie_token = new Cookie("MultiLoginError2", models2Json(userModels, true, sign));
|
Cookie cookie_token = new Cookie("MultiLoginError2", models2Json(userModel, true, sign));
|
||||||
cookie_token.setPath("/");
|
cookie_token.setPath("/");
|
||||||
response.addCookie(cookie_token);
|
response.addCookie(cookie_token);
|
||||||
userModels = userModels.stream().filter(mode -> !StringUtils.equals(mode.getToken(), sign)).collect(Collectors.toSet());
|
|
||||||
TokenCacheUtils.resetOnlinePools(userId, userModels);
|
|
||||||
DataEaseException.throwException("MultiLoginError");
|
DataEaseException.throwException("MultiLoginError");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (writeOnline && !StringUtils.equals("0", multiLoginType)) {
|
||||||
TokenCacheUtils.add2OnlinePools(sign, userId);
|
TokenCacheUtils.add2OnlinePools(sign, userId);
|
||||||
}
|
}
|
||||||
return sign;
|
return sign;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.dataease.commons.utils;
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import io.dataease.commons.model.OnlineUserModel;
|
import io.dataease.commons.model.OnlineUserModel;
|
||||||
import io.dataease.listener.util.CacheUtils;
|
import io.dataease.listener.util.CacheUtils;
|
||||||
import io.dataease.service.system.SystemParameterService;
|
import io.dataease.service.system.SystemParameterService;
|
||||||
@ -7,12 +8,9 @@ import org.apache.commons.lang3.ObjectUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.core.SetOperations;
|
|
||||||
import org.springframework.data.redis.core.ValueOperations;
|
import org.springframework.data.redis.core.ValueOperations;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +26,8 @@ public class TokenCacheUtils {
|
|||||||
|
|
||||||
private static Long expTime;
|
private static Long expTime;
|
||||||
|
|
||||||
|
private static Gson gson = new Gson();
|
||||||
|
|
||||||
@Value("${spring.cache.type:ehcache}")
|
@Value("${spring.cache.type:ehcache}")
|
||||||
public void setCacheType(String cacheType) {
|
public void setCacheType(String cacheType) {
|
||||||
TokenCacheUtils.cacheType = cacheType;
|
TokenCacheUtils.cacheType = cacheType;
|
||||||
@ -62,17 +62,6 @@ public class TokenCacheUtils {
|
|||||||
CacheUtils.flush(KEY);
|
CacheUtils.flush(KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void remove(String token) {
|
|
||||||
if (useRedis()) {
|
|
||||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
|
||||||
String key = KEY + token;
|
|
||||||
if (redisTemplate.hasKey(key)) {
|
|
||||||
redisTemplate.delete(key);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CacheUtils.remove(KEY, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean invalid(String token) {
|
public static boolean invalid(String token) {
|
||||||
if (useRedis()) {
|
if (useRedis()) {
|
||||||
@ -83,36 +72,17 @@ public class TokenCacheUtils {
|
|||||||
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString());
|
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resetOnlinePools(Long userId, Set<OnlineUserModel> sets) {
|
public static void add2OnlinePools(String token, Long userId) {
|
||||||
|
OnlineUserModel model = buildModel(token);
|
||||||
if (useRedis()) {
|
if (useRedis()) {
|
||||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
ValueOperations valueOperations = cacheHandler();
|
||||||
redisTemplate.delete(ONLINE_TOKEN_POOL_KEY + userId);
|
valueOperations.set(ONLINE_TOKEN_POOL_KEY + userId, model, expTime, TimeUnit.MINUTES);
|
||||||
SetOperations setOperations = redisTemplate.opsForSet();
|
|
||||||
Object[] modelArray = sets.stream().toArray();
|
|
||||||
setOperations.add(ONLINE_TOKEN_POOL_KEY + userId, modelArray);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CacheUtils.removeAll(ONLINE_TOKEN_POOL_KEY);
|
|
||||||
CacheUtils.put(ONLINE_TOKEN_POOL_KEY, userId, sets, null, null);
|
|
||||||
CacheUtils.flush(ONLINE_TOKEN_POOL_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void add2OnlinePools(String token, Long userId) {
|
Long time = expTime * 60;
|
||||||
if (useRedis()) {
|
Double v = time * 0.6;
|
||||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
CacheUtils.put(ONLINE_TOKEN_POOL_KEY, userId, model, time.intValue(), v.intValue());
|
||||||
SetOperations setOperations = redisTemplate.opsForSet();
|
|
||||||
setOperations.add(ONLINE_TOKEN_POOL_KEY + userId, buildModel(token));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object listObj = null;
|
|
||||||
Set<OnlineUserModel> models = null;
|
|
||||||
if (ObjectUtils.isEmpty(listObj = CacheUtils.get(ONLINE_TOKEN_POOL_KEY, userId))) {
|
|
||||||
models = new LinkedHashSet<>();
|
|
||||||
} else {
|
|
||||||
models = (Set<OnlineUserModel>) listObj;
|
|
||||||
}
|
|
||||||
models.add(buildModel(token));
|
|
||||||
CacheUtils.put(ONLINE_TOKEN_POOL_KEY, userId, models, null, null);
|
|
||||||
CacheUtils.flush(ONLINE_TOKEN_POOL_KEY);
|
CacheUtils.flush(ONLINE_TOKEN_POOL_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,16 +91,18 @@ public class TokenCacheUtils {
|
|||||||
return service.multiLoginType();
|
return service.multiLoginType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<OnlineUserModel> onlineUserTokens(Long userId) {
|
public static OnlineUserModel onlineUserToken(Long userId) {
|
||||||
if (useRedis()) {
|
if (useRedis()) {
|
||||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
ValueOperations valueOperations = cacheHandler();
|
||||||
SetOperations setOperations = redisTemplate.opsForSet();
|
Object obj = valueOperations.get(ONLINE_TOKEN_POOL_KEY + userId);
|
||||||
Set tokens = setOperations.members(ONLINE_TOKEN_POOL_KEY + userId);
|
if (ObjectUtils.isNotEmpty(obj)) return (OnlineUserModel) obj;
|
||||||
return tokens;
|
return null;
|
||||||
}
|
}
|
||||||
Object o = CacheUtils.get(ONLINE_TOKEN_POOL_KEY, userId);
|
Object o = CacheUtils.get(ONLINE_TOKEN_POOL_KEY, userId);
|
||||||
if (ObjectUtils.isNotEmpty(o))
|
if (ObjectUtils.isNotEmpty(o)) {
|
||||||
return (Set<OnlineUserModel>) o;
|
OnlineUserModel userModel = gson.fromJson(gson.toJson(o), OnlineUserModel.class);
|
||||||
|
return userModel;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user