From 593630e04dae465fe9280787d2424be952b97c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Wed, 10 Dec 2025 13:17:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0wvp=E8=BD=AC=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/filter/WvpAccessTokenFilter.java | 100 ++++++ .../com/tuoheng/gateway/utils/WvpClient.java | 289 ++++++++++++++++++ src/main/resources/application.yml | 8 + 3 files changed, 397 insertions(+) create mode 100644 src/main/java/com/tuoheng/gateway/filter/WvpAccessTokenFilter.java create mode 100644 src/main/java/com/tuoheng/gateway/utils/WvpClient.java diff --git a/src/main/java/com/tuoheng/gateway/filter/WvpAccessTokenFilter.java b/src/main/java/com/tuoheng/gateway/filter/WvpAccessTokenFilter.java new file mode 100644 index 0000000..30a7761 --- /dev/null +++ b/src/main/java/com/tuoheng/gateway/filter/WvpAccessTokenFilter.java @@ -0,0 +1,100 @@ +package com.tuoheng.gateway.filter; + +import com.tuoheng.gateway.utils.WvpClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * WVP Access Token 过滤器 + * 用于为 WVP 请求添加或替换 access-token 请求头 + */ +@Slf4j +@Component +public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory { + + private static String cachedAccessToken = null; + private static final Object LOCK = new Object(); + + public WvpAccessTokenFilter() { + super(Config.class); + } + + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + try { + // 获取 access token + String accessToken = getAccessToken(); + + log.info("WVP 请求 - 原始路径: {}", exchange.getRequest().getURI().getPath()); + log.info("WVP 请求 - 原始URI: {}", exchange.getRequest().getURI()); + log.info("WVP 请求 - 添加 access-token: {}", accessToken.substring(0, Math.min(20, accessToken.length())) + "..."); + log.info("WVP 请求 - 完整 access-token: {}", accessToken); + + // 修改请求,添加或替换 access-token 请求头 + ServerHttpRequest modifiedRequest = exchange.getRequest().mutate() + .header("access-token", accessToken) + .build(); + + // 创建新的 exchange + ServerWebExchange modifiedExchange = exchange.mutate() + .request(modifiedRequest) + .build(); + + log.info("WVP 请求 - 修改后的请求头: {}", modifiedRequest.getHeaders()); + + return chain.filter(modifiedExchange).then(Mono.fromRunnable(() -> { + log.info("WVP 响应 - Status: {}", modifiedExchange.getResponse().getStatusCode()); + log.info("WVP 响应 - Headers: {}", modifiedExchange.getResponse().getHeaders()); + })); + } catch (Exception e) { + log.error("获取 WVP access token 失败", e); + // 即使获取 token 失败,也继续转发请求 + return chain.filter(exchange); + } + }; + } + + /** + * 获取 access token,使用缓存机制 + * 如果缓存为空,则调用 WvpClient.login 获取新的 token + */ + private String getAccessToken() throws Exception { + if (cachedAccessToken == null) { + synchronized (LOCK) { + if (cachedAccessToken == null) { + log.info("缓存中没有 access token,正在登录 WVP..."); + WvpClient.LoginResponse loginResponse = WvpClient.login("admin", "admin"); + if (loginResponse.getCode() == 0 && loginResponse.getData() != null) { + cachedAccessToken = loginResponse.getData().getAccessToken(); + log.info("WVP 登录成功,获取到 access token"); + } else { + throw new Exception("WVP 登录失败: " + loginResponse.getMsg()); + } + } + } + } + return cachedAccessToken; + } + + /** + * 清除缓存的 access token(可用于 token 过期时重新获取) + */ + public static void clearCachedToken() { + synchronized (LOCK) { + cachedAccessToken = null; + log.info("已清除缓存的 WVP access token"); + } + } + + /** + * 配置类 + */ + public static class Config { + } +} diff --git a/src/main/java/com/tuoheng/gateway/utils/WvpClient.java b/src/main/java/com/tuoheng/gateway/utils/WvpClient.java new file mode 100644 index 0000000..310f8e8 --- /dev/null +++ b/src/main/java/com/tuoheng/gateway/utils/WvpClient.java @@ -0,0 +1,289 @@ +package com.tuoheng.gateway.utils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import com.google.gson.Gson; + +public class WvpClient { + + private static final String WVP_BASE_URL = "http://114.67.89.4:9090"; + private static final Gson gson = new Gson(); + + /** + * WVP登录响应对象 + */ + public static class LoginResponse { + private int code; + private String msg; + private LoginData data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public LoginData getData() { + return data; + } + + public void setData(LoginData data) { + this.data = data; + } + + @Override + public String toString() { + return gson.toJson(this); + } + } + + /** + * 登录数据对象 + */ + public static class LoginData { + private String accessToken; + private String serverId; + private int id; + private boolean enabled; + private String password; + private Role role; + private String username; + private String pushKey; + private boolean accountNonExpired; + private boolean accountNonLocked; + private boolean credentialsNonExpired; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getServerId() { + return serverId; + } + + public void setServerId(String serverId) { + this.serverId = serverId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPushKey() { + return pushKey; + } + + public void setPushKey(String pushKey) { + this.pushKey = pushKey; + } + + public boolean isAccountNonExpired() { + return accountNonExpired; + } + + public void setAccountNonExpired(boolean accountNonExpired) { + this.accountNonExpired = accountNonExpired; + } + + public boolean isAccountNonLocked() { + return accountNonLocked; + } + + public void setAccountNonLocked(boolean accountNonLocked) { + this.accountNonLocked = accountNonLocked; + } + + public boolean isCredentialsNonExpired() { + return credentialsNonExpired; + } + + public void setCredentialsNonExpired(boolean credentialsNonExpired) { + this.credentialsNonExpired = credentialsNonExpired; + } + } + + /** + * 角色对象 + */ + public static class Role { + private int id; + private String name; + private String authority; + private String createTime; + private String updateTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + } + + /** + * 计算MD5哈希值 + * + * @param input 输入字符串 + * @return MD5哈希值(小写) + * @throws Exception 如果计算失败 + */ + private static String md5(String input) throws Exception { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + /** + * WVP用户登录 + * + * @param username 用户名 + * @param password 密码(明文) + * @return 登录响应对象 + * @throws Exception 如果请求失败 + */ + public static LoginResponse login(String username, String password) throws Exception { + // 计算密码的MD5值 + String passwordMd5 = md5(password); + + // 构建 URL 参数 + StringBuilder urlBuilder = new StringBuilder(WVP_BASE_URL); + urlBuilder.append("/api/user/login?"); + urlBuilder.append("username=").append(URLEncoder.encode(username, StandardCharsets.UTF_8.name())); + urlBuilder.append("&password=").append(passwordMd5); + + // 创建 HTTP 连接 + URL url = new URL(urlBuilder.toString()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + // 获取响应 + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + // 解析JSON响应 + return gson.fromJson(response.toString(), LoginResponse.class); + } else { + throw new Exception("HTTP 请求失败,状态码: " + responseCode); + } + } + + public static void main(String[] args) { + try { + // 调用 login 方法 + LoginResponse loginResponse = login("admin", "admin"); + System.out.println("登录响应结果:"); + System.out.println(loginResponse); + System.out.println("\nAccess Token: " + loginResponse.getData().getAccessToken()); + System.out.println("Username: " + loginResponse.getData().getUsername()); + System.out.println("Role: " + loginResponse.getData().getRole().getName()); + } catch (Exception e) { + System.err.println("登录失败: " + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fed78aa..76e4095 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,6 +22,14 @@ spring: - RewritePath=/zlm/(?.*), /$\{segment} - AddRequestParameter=secret, su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf + - id: wvp-route + uri: http://114.67.89.4:9090 + predicates: + - Path=/wvp/** + filters: + - RewritePath=/wvp/(?.*), /$\{segment} + - name: WvpAccessTokenFilter + # 启用 JWT 认证(默认为 false,即不启用) # spring.security.oauth2.resourceserver.jwt.enabled: false