This commit is contained in:
parent
d80502c681
commit
2b702197fa
|
|
@ -5,11 +5,18 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WVP Access Token 过滤器
|
* WVP Access Token 过滤器
|
||||||
* 用于为 WVP 请求添加或替换 access-token 请求头
|
* 用于为 WVP 请求添加或替换 access-token 请求头
|
||||||
|
|
@ -19,9 +26,22 @@ public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory<WvpAccess
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(WvpAccessTokenFilter.class);
|
private static final Logger log = LoggerFactory.getLogger(WvpAccessTokenFilter.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WVP token 过期时间(分钟)- 从 WVP 源码中获取
|
||||||
|
*/
|
||||||
|
private static final long TOKEN_EXPIRATION_MINUTES = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提前刷新时间(分钟)- 在 token 过期前 5 分钟刷新
|
||||||
|
*/
|
||||||
|
private static final long REFRESH_BEFORE_EXPIRATION_MINUTES = 5;
|
||||||
|
|
||||||
private static String cachedAccessToken = null;
|
private static String cachedAccessToken = null;
|
||||||
|
private static LocalDateTime tokenExpirationTime = null;
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
|
private final WebClient webClient = WebClient.builder().build();
|
||||||
|
|
||||||
public WvpAccessTokenFilter() {
|
public WvpAccessTokenFilter() {
|
||||||
super(Config.class);
|
super(Config.class);
|
||||||
}
|
}
|
||||||
|
|
@ -29,53 +49,100 @@ public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory<WvpAccess
|
||||||
@Override
|
@Override
|
||||||
public GatewayFilter apply(Config config) {
|
public GatewayFilter apply(Config config) {
|
||||||
return (exchange, chain) -> {
|
return (exchange, chain) -> {
|
||||||
try {
|
String path = exchange.getRequest().getURI().getPath();
|
||||||
// 获取 access token
|
String query = exchange.getRequest().getURI().getQuery();
|
||||||
String accessToken = getAccessToken();
|
String fullPath = query != null ? path + "?" + query : path;
|
||||||
|
|
||||||
log.info("WVP 请求 - 原始路径: {}", exchange.getRequest().getURI().getPath());
|
log.info("WVP 请求 - 路径: {}", fullPath);
|
||||||
log.info("WVP 请求 - 添加 access-token");
|
|
||||||
|
|
||||||
// 修改请求,添加或替换 access-token 请求头
|
// 使用 WebClient 直接调用 WVP,支持自动重试
|
||||||
ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
|
return callWvpWithRetry(fullPath, exchange, 0)
|
||||||
.header("access-token", accessToken)
|
.flatMap(responseBody -> {
|
||||||
.build();
|
// 将响应写回客户端
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
|
||||||
// 创建新的 exchange
|
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||||
ServerWebExchange modifiedExchange = exchange.mutate()
|
DataBuffer buffer = bufferFactory.wrap(responseBody.getBytes(StandardCharsets.UTF_8));
|
||||||
.request(modifiedRequest)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return chain.filter(modifiedExchange).then(Mono.fromRunnable(() -> {
|
return response.writeWith(Mono.just(buffer));
|
||||||
log.info("WVP 响应 - Status: {}", modifiedExchange.getResponse().getStatusCode());
|
})
|
||||||
}));
|
.onErrorResume(e -> {
|
||||||
} catch (Exception e) {
|
log.error("WVP 请求失败", e);
|
||||||
log.error("获取 WVP access token 失败", e);
|
|
||||||
// 即使获取 token 失败,也继续转发请求
|
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 access token,使用缓存机制
|
* 调用 WVP 接口,支持自动重试
|
||||||
* 如果缓存为空,则调用 WvpTokenClient.login 获取新的 token
|
*
|
||||||
|
* @param path 请求路径
|
||||||
|
* @param exchange ServerWebExchange
|
||||||
|
* @param retryCount 重试次数
|
||||||
|
* @return 响应体
|
||||||
|
*/
|
||||||
|
private Mono<String> callWvpWithRetry(String path, ServerWebExchange exchange, int retryCount) {
|
||||||
|
try {
|
||||||
|
String accessToken = getAccessToken();
|
||||||
|
String wvpUrl = "http://wvp-pro:18978" + path;
|
||||||
|
|
||||||
|
log.debug("调用 WVP 接口: {}, access-token: {}", wvpUrl, accessToken);
|
||||||
|
|
||||||
|
return webClient.get()
|
||||||
|
.uri(wvpUrl)
|
||||||
|
.header("access-token", accessToken)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.onErrorResume(e -> {
|
||||||
|
log.error("WVP 请求失败,尝试刷新 token 并重试", e);
|
||||||
|
if (retryCount < 1) {
|
||||||
|
// 清除缓存的 token,下次会重新获取
|
||||||
|
clearCachedToken();
|
||||||
|
// 重试一次
|
||||||
|
return callWvpWithRetry(path, exchange, retryCount + 1);
|
||||||
|
}
|
||||||
|
return Mono.error(e);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取 access token 失败", e);
|
||||||
|
return Mono.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 access token,使用缓存机制并支持提前刷新
|
||||||
|
* 如果缓存为空或即将过期,则调用 WvpTokenClient.login 获取新的 token
|
||||||
*/
|
*/
|
||||||
private String getAccessToken() throws Exception {
|
private String getAccessToken() throws Exception {
|
||||||
if (cachedAccessToken == null) {
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
|
// 检查 token 是否需要刷新(不存在或即将过期)
|
||||||
|
if (cachedAccessToken == null || tokenExpirationTime == null ||
|
||||||
|
now.plusMinutes(REFRESH_BEFORE_EXPIRATION_MINUTES).isAfter(tokenExpirationTime)) {
|
||||||
|
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
if (cachedAccessToken == null) {
|
// 双重检查
|
||||||
log.info("缓存中没有 access token,正在登录 WVP...");
|
now = LocalDateTime.now();
|
||||||
|
if (cachedAccessToken == null || tokenExpirationTime == null ||
|
||||||
|
now.plusMinutes(REFRESH_BEFORE_EXPIRATION_MINUTES).isAfter(tokenExpirationTime)) {
|
||||||
|
|
||||||
|
log.info("Token 不存在或即将过期,正在刷新 WVP access token...");
|
||||||
WvpTokenClient.LoginResponse loginResponse = WvpTokenClient.login("admin", "admin");
|
WvpTokenClient.LoginResponse loginResponse = WvpTokenClient.login("admin", "admin");
|
||||||
|
|
||||||
if (loginResponse.getCode() == 0 && loginResponse.getData() != null) {
|
if (loginResponse.getCode() == 0 && loginResponse.getData() != null) {
|
||||||
cachedAccessToken = loginResponse.getData().getAccessToken();
|
cachedAccessToken = loginResponse.getData().getAccessToken();
|
||||||
log.info("WVP 登录成功,获取到 access token");
|
// 设置过期时间为当前时间 + TOKEN_EXPIRATION_MINUTES
|
||||||
|
tokenExpirationTime = now.plusMinutes(TOKEN_EXPIRATION_MINUTES);
|
||||||
|
log.info("WVP 登录成功,获取到 access token,过期时间: {}", tokenExpirationTime);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("WVP 登录失败: " + loginResponse.getMsg());
|
throw new Exception("WVP 登录失败: " + loginResponse.getMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedAccessToken;
|
return cachedAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,6 +152,7 @@ public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory<WvpAccess
|
||||||
public static void clearCachedToken() {
|
public static void clearCachedToken() {
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
cachedAccessToken = null;
|
cachedAccessToken = null;
|
||||||
|
tokenExpirationTime = null;
|
||||||
log.info("已清除缓存的 WVP access token");
|
log.info("已清除缓存的 WVP access token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue