refactor: 网关消除魔法值,scope/事件/请求头/MCP 协议等改为枚举与常量
- 新增 ScopeMatcher、GatewayAuthorities、JwtClaims、GatewayHeaders、InternalPaths、McpProtocol/McpToolArgs 等常量与枚举 - Webhook 消息体改用 ObjectMapper 构建,修复原先仅转义引号的问题 - 管理接口与 OpenAPI 控制器的默认值、响应字段、演示数据集中到 AdminDefaults / OpenApiFields Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,17 @@ public class IpUtils {
|
||||
private static final String UNKNOWN = "unknown";
|
||||
private static final String LOCALHOST_IPV4 = "127.0.0.1";
|
||||
private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
|
||||
private static final String WILDCARD = "*";
|
||||
private static final String ANY_CIDR = "0.0.0.0/0";
|
||||
private static final String CIDR_SEPARATOR = "/";
|
||||
private static final String IP_LIST_SEPARATOR = ",";
|
||||
/** 代理配置的分隔符:逗号、分号、空白 */
|
||||
private static final String PROXY_CONFIG_SPLIT_REGEX = "[,;\\s]+";
|
||||
/** 白名单配置的分隔符:逗号、分号、中文逗号、换行 */
|
||||
private static final String WHITELIST_SPLIT_REGEX = "[,;,\\n\\r]+";
|
||||
private static final int BITS_PER_BYTE = 8;
|
||||
private static final int BYTE_MASK = 0xFF;
|
||||
private static final int CIDR_PART_COUNT = 2;
|
||||
|
||||
/**
|
||||
* 默认信任的内网/本地反向代理 IP 网段 (如本地 Nginx / 宿主机代理)
|
||||
@@ -34,7 +45,7 @@ public class IpUtils {
|
||||
public static void setTrustedProxies(String proxiesConfig) {
|
||||
if (StringUtils.hasText(proxiesConfig)) {
|
||||
TRUSTED_PROXIES.clear();
|
||||
for (String p : proxiesConfig.split("[,;\\s]+")) {
|
||||
for (String p : proxiesConfig.split(PROXY_CONFIG_SPLIT_REGEX)) {
|
||||
if (StringUtils.hasText(p)) {
|
||||
TRUSTED_PROXIES.add(p.trim());
|
||||
}
|
||||
@@ -61,23 +72,23 @@ public class IpUtils {
|
||||
}
|
||||
|
||||
// 仅在确认对端为受信任反向代理的前提下,提取代理传递的源 IP
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
String ip = request.getHeader(GatewayHeaders.FORWARDED_FOR);
|
||||
if (isInvalidIp(ip)) {
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
ip = request.getHeader(GatewayHeaders.REAL_IP);
|
||||
}
|
||||
if (isInvalidIp(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
ip = request.getHeader(GatewayHeaders.PROXY_CLIENT_IP);
|
||||
}
|
||||
if (isInvalidIp(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
ip = request.getHeader(GatewayHeaders.WL_PROXY_CLIENT_IP);
|
||||
}
|
||||
if (isInvalidIp(ip)) {
|
||||
ip = remoteAddr;
|
||||
}
|
||||
|
||||
// 多级反向代理会有多个逗号分隔的 IP,首个为客户端真实源 IP
|
||||
if (StringUtils.hasText(ip) && ip.contains(",")) {
|
||||
for (String subIp : ip.split(",")) {
|
||||
if (StringUtils.hasText(ip) && ip.contains(IP_LIST_SEPARATOR)) {
|
||||
for (String subIp : ip.split(IP_LIST_SEPARATOR)) {
|
||||
String trimmed = subIp.trim();
|
||||
if (!isInvalidIp(trimmed)) {
|
||||
ip = trimmed;
|
||||
@@ -123,7 +134,7 @@ public class IpUtils {
|
||||
|
||||
String normalizedClientIp = LOCALHOST_IPV6.equals(clientIp.trim()) ? LOCALHOST_IPV4 : clientIp.trim();
|
||||
|
||||
String[] rules = whitelist.split("[,;,\\n\\r]+");
|
||||
String[] rules = whitelist.split(WHITELIST_SPLIT_REGEX);
|
||||
for (String rule : rules) {
|
||||
String pattern = rule.trim();
|
||||
if (!pattern.isEmpty() && matchIp(normalizedClientIp, pattern)) {
|
||||
@@ -148,15 +159,15 @@ public class IpUtils {
|
||||
if (LOCALHOST_IPV6.equals(ip)) ip = LOCALHOST_IPV4;
|
||||
if (LOCALHOST_IPV6.equals(pattern)) pattern = LOCALHOST_IPV4;
|
||||
|
||||
if ("*".equals(pattern) || "0.0.0.0/0".equals(pattern)) {
|
||||
if (WILDCARD.equals(pattern) || ANY_CIDR.equals(pattern)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pattern.contains("/")) {
|
||||
if (pattern.contains(CIDR_SEPARATOR)) {
|
||||
return matchCidr(ip, pattern);
|
||||
}
|
||||
|
||||
if (pattern.contains("*")) {
|
||||
if (pattern.contains(WILDCARD)) {
|
||||
return matchWildcard(ip, pattern);
|
||||
}
|
||||
|
||||
@@ -164,14 +175,14 @@ public class IpUtils {
|
||||
}
|
||||
|
||||
private static boolean matchWildcard(String ip, String pattern) {
|
||||
String regex = pattern.replace(".", "\\.").replace("*", ".*");
|
||||
String regex = pattern.replace(".", "\\.").replace(WILDCARD, ".*");
|
||||
return ip.matches(regex);
|
||||
}
|
||||
|
||||
private static boolean matchCidr(String ip, String cidr) {
|
||||
try {
|
||||
String[] parts = cidr.split("/");
|
||||
if (parts.length != 2) return false;
|
||||
String[] parts = cidr.split(CIDR_SEPARATOR);
|
||||
if (parts.length != CIDR_PART_COUNT) return false;
|
||||
|
||||
String network = parts[0];
|
||||
int prefixLength = Integer.parseInt(parts[1]);
|
||||
@@ -181,15 +192,15 @@ public class IpUtils {
|
||||
|
||||
if (ipBytes.length != netBytes.length) return false;
|
||||
|
||||
int byteCount = prefixLength / 8;
|
||||
int bitCount = prefixLength % 8;
|
||||
int byteCount = prefixLength / BITS_PER_BYTE;
|
||||
int bitCount = prefixLength % BITS_PER_BYTE;
|
||||
|
||||
for (int i = 0; i < byteCount; i++) {
|
||||
if (ipBytes[i] != netBytes[i]) return false;
|
||||
}
|
||||
|
||||
if (bitCount > 0 && byteCount < ipBytes.length) {
|
||||
int mask = (0xFF << (8 - bitCount)) & 0xFF;
|
||||
int mask = (BYTE_MASK << (BITS_PER_BYTE - bitCount)) & BYTE_MASK;
|
||||
return (ipBytes[byteCount] & mask) == (netBytes[byteCount] & mask);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user