feat(调用第三方微服务): 处理Nacos请求转发

1. 调用Nacos登录接口后将响应结果中的accessToken添加到请求头中
2. 增加Redis对Sentinel和Nacos的Token进行缓存,减少登录接口重复调用次数,加快第三方开源软件调用的响应速度

Signed-off-by: OTTO <731554297@qq.com>
This commit is contained in:
OTTO 2024-10-18 09:43:46 +08:00
parent 62495f0f33
commit e2138020be
4 changed files with 110 additions and 30 deletions

View File

@ -208,4 +208,15 @@ public class CacheConstants
public static String getGitlinkOrgIdOpenEnterpriseKey(Long gitlinkOrgId) {
return GITLINK_ORG_ID_OPEN_ENTERPRISE_KEY + gitlinkOrgId;
}
/**
* Sentinel Token缓存Key
*/
public final static String SENTINEL_TOKEN = "sentinel_token";
/**
* Nacos Token缓存Key
*/
public static final String NACOS_TOKEN = "nacos_token";
}

View File

@ -22,6 +22,10 @@ public class TokenConstants {
* Sentinel令牌标识
*/
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
/**
* Sentinel令牌标识
*/
public static final String Nacos_Token_Key = "Accesstoken";
/**
* Cookie中令牌标识
*/

View File

@ -0,0 +1,35 @@
package com.microservices.gateway;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.threadPool.ThreadPoolExecutorWrap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author OTTO
*/
public class CustomExecutorFactory {
/**
* 创建线程池
* 存在并发处理的情况设置核心线程为2设置有界队列长度为100最大线程数为10
* 当超出队列已满且达到最大线程数时抛出异常
* Ncpu=CPU数量
* Ucpu=目标CPU的使用率0<=Ucpu<=1
* W/C=任务等待时间与任务计算时间的比率
* Nthreads =Ncpu*Ucpu*(1+W/C)
*/
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorWrap(
4
, 10
, 10
, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(100)
, Executors.defaultThreadFactory()
, (r, executor) -> {
throw new ServiceException("目前处理的人太多了,请稍后再试");
}
);
}

View File

@ -1,5 +1,6 @@
package com.microservices.gateway.filter;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.constant.CacheConstants;
import com.microservices.common.core.constant.HttpStatus;
import com.microservices.common.core.constant.SecurityConstants;
@ -11,6 +12,7 @@ import com.microservices.common.core.utils.JwtUtils;
import com.microservices.common.core.utils.ServletUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.redis.service.RedisService;
import com.microservices.gateway.CustomExecutorFactory;
import com.microservices.gateway.config.properties.IgnoreWhiteProperties;
import com.microservices.system.api.RemoteGatewayService;
import com.microservices.system.api.RemoteUserService;
@ -31,15 +33,14 @@ import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
/**
* 网关鉴权
@ -63,7 +64,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
@Autowired
private RemoteGatewayService remoteGatewayService;
ExecutorService executorService = Executors.newFixedThreadPool(1);
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
/**
* 处理第三方工具请求
@ -80,35 +81,64 @@ public class AuthFilter implements GlobalFilter, Ordered {
if (StringUtils.isNotEmpty(CookieUtil.getCookieValue(cookie, TokenConstants.Sentinel_Token_Key))) {
cookie = CookieUtil.removeCookieKey(cookie, TokenConstants.Sentinel_Token_Key);
}
// 网关采用异步架构所以此处需要通过异步请求获取Sentinel Token
Future<Response> future = executorService.submit(() -> remoteGatewayService.loginSentinel("sentinel", "sentinel"));
try {
Response response = future.get(1, TimeUnit.SECONDS);
Map<String, Collection<String>> header = response.headers();
if (header != null && header.containsKey("set-cookie")) {
String sentinelCookie = header.get("set-cookie").iterator().next();
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
String sentinelCookie = null;
if (redisService.hasKey(CacheConstants.SENTINEL_TOKEN)) {
sentinelCookie = redisService.getCacheObject(CacheConstants.SENTINEL_TOKEN);
} else {
// 网关采用异步架构所以此处需要通过异步请求获取Sentinel Token
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel("sentinel", "sentinel"));
try {
Response response = future.get(1, TimeUnit.SECONDS);
Map<String, Collection<String>> header = response.headers();
if (header != null && header.containsKey("set-cookie")) {
sentinelCookie = header.get("set-cookie").iterator().next();
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 12L, TimeUnit.HOURS);
}
} catch (TimeoutException e) {
log.error("获取Sentinel Token超时");
} catch (InterruptedException | ExecutionException e) {
log.error("获取Sentinel Token失败{}", e.getMessage());
}
} catch (Exception e) {
log.error("获取Sentinel Token失败{0}", e);
}
if (StringUtils.isNotEmpty(sentinelCookie)) {
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
}
}
// 处理Nacos请求
if (url.toLowerCase().startsWith("/nacos")) {
// 网关采用异步架构所以此处需要通过异步请求获取Nacos Token
Future<Response> future = executorService.submit(() -> remoteGatewayService.loginNacos("nacos", "nacos"));
try {
Response res = future.get(1, TimeUnit.SECONDS);
StringWriter writer = new StringWriter();
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
String str = writer.toString();
System.out.println(str);
} catch (Exception e) {
log.error("获取Nacos Token失败{0}", e);
String nacosToken = null;
if (redisService.hasKey(CacheConstants.NACOS_TOKEN)) {
nacosToken = redisService.getCacheObject(CacheConstants.NACOS_TOKEN);
} else {
Map<String, String> nacosMap = new HashMap<>();
nacosMap.put("username", "nacos");
nacosMap.put("password", "nacos");
// 网关采用异步架构所以此处需要通过异步请求获取Nacos Token
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
try {
Response res = future.get(1, TimeUnit.SECONDS);
StringWriter writer = new StringWriter();
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
String str = writer.toString();
JSONObject resJsonObject = JSONObject.parseObject(str);
nacosToken = resJsonObject.getString("accessToken");
Long tokenTtl = resJsonObject.getLong("tokenTtl");
if (nacosToken != null && tokenTtl != null) {
redisService.setCacheObject(CacheConstants.NACOS_TOKEN, nacosToken, tokenTtl - 10, TimeUnit.SECONDS);
} else {
throw new ServiceException("Nacos服务获取Token失败");
}
} catch (TimeoutException e) {
log.error("获取Nacos Token超时");
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
log.error("获取Nacos Token失败{}", e.getMessage());
}
}
if (StringUtils.isNotEmpty(nacosToken)) {
mutate.header(TokenConstants.Nacos_Token_Key, nacosToken);
}
}
}
@Override
@ -176,7 +206,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
boolean hasUserIdentifyList = redisService.hasKey(redisKey);
if (!hasUserIdentifyList) {
// 网关采用异步架构所以此处需要通过异步请求获取本系统Token
Future<R<List<SysUserDeptRole>>> future = executorService.submit(
Future<R<List<SysUserDeptRole>>> future = threadPoolExecutor.submit(
() -> remoteUserService.getSysUserDeptRoleListByUserName(username, SecurityConstants.INNER));
try {
List<SysUserDeptRole> feignResult = FeignUtils.getReturnData(
@ -201,7 +231,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
if (token != null) {
// 网关采用异步架构所以此处需要通过异步请求获取本系统Token
Future<R<Boolean>> future = executorService.submit(
Future<R<Boolean>> future = threadPoolExecutor.submit(
() -> remoteUserService.checkGitLinkUserLogin(token, SecurityConstants.INNER));
try {
Boolean feignResult = FeignUtils.getReturnData(
@ -254,7 +284,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
private String getGitLinkToken(String cookie) {
if (StringUtils.isNotEmpty(cookie)) {
// 网关采用异步架构所以此处需要通过异步请求获取本系统Token
Future<R<String>> future = executorService.submit(() -> remoteUserService
Future<R<String>> future = threadPoolExecutor.submit(() -> remoteUserService
.getSysUserTokenByGitLinkCookie(cookie, SecurityConstants.INNER));
R<String> feignResult;
try {