feat: Enhance RequestUrlUtils to handle browser Referer for public URL resolution and add corresponding unit tests
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package com.ruoyi.common.utils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* 请求公开地址工具。
|
||||
@@ -24,10 +26,17 @@ public final class RequestUrlUtils
|
||||
String forwarded = firstForwardedValue(forwardedHeader, "host");
|
||||
String forwardedHost = firstHeaderValue(request.getHeader("X-Forwarded-Host"));
|
||||
String hostHeader = request.getHeader("Host");
|
||||
boolean hasPublicHost = !isBlank(forwarded) || !isBlank(forwardedHost) || !isBlank(hostHeader);
|
||||
String requestHost = firstNonBlank(hostHeader, request.getServerName());
|
||||
URI browserOrigin = isInternalHost(requestHost)
|
||||
? firstBrowserOrigin(request)
|
||||
: null;
|
||||
String browserHost = browserOrigin == null ? null : getAuthority(browserOrigin);
|
||||
boolean hasPublicHost = !isBlank(forwarded) || !isBlank(forwardedHost)
|
||||
|| !isBlank(hostHeader) || browserOrigin != null;
|
||||
String host = firstNonBlank(
|
||||
forwarded,
|
||||
forwardedHost,
|
||||
browserHost,
|
||||
hostHeader,
|
||||
request.getServerName());
|
||||
host = normalizeHost(host);
|
||||
@@ -35,12 +44,17 @@ public final class RequestUrlUtils
|
||||
String scheme = firstNonBlank(
|
||||
firstForwardedValue(request.getHeader("Forwarded"), "proto"),
|
||||
firstHeaderValue(request.getHeader("X-Forwarded-Proto")),
|
||||
browserOrigin == null ? null : browserOrigin.getScheme(),
|
||||
request.getScheme());
|
||||
scheme = normalizeScheme(scheme, request.getScheme());
|
||||
|
||||
String forwardedPort = firstNonBlank(
|
||||
extractPort(forwarded),
|
||||
firstHeaderValue(request.getHeader("X-Forwarded-Port")));
|
||||
firstHeaderValue(request.getHeader("X-Forwarded-Port")),
|
||||
browserOrigin == null ? null : String.valueOf(browserOrigin.getPort()));
|
||||
if ("-1".equals(forwardedPort)) {
|
||||
forwardedPort = null;
|
||||
}
|
||||
if (!hasPort(host) && shouldIncludePort(forwardedPort, scheme)) {
|
||||
host += ":" + forwardedPort;
|
||||
}
|
||||
@@ -53,6 +67,63 @@ public final class RequestUrlUtils
|
||||
return scheme + "://" + host + (contextPath == null ? "" : contextPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反向代理未透传 Host 时,Servlet 可能只能看到 127.0.0.1:9091。
|
||||
* 对浏览器请求,Origin/Referer 仍然包含用户实际访问的公开地址,作为兜底来源。
|
||||
*/
|
||||
private static URI firstBrowserOrigin(HttpServletRequest request)
|
||||
{
|
||||
URI origin = parseHttpUri(firstHeaderValue(request.getHeader("Origin")));
|
||||
return origin != null
|
||||
? origin
|
||||
: parseHttpUri(firstHeaderValue(request.getHeader("Referer")));
|
||||
}
|
||||
|
||||
private static URI parseHttpUri(String value)
|
||||
{
|
||||
if (isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
URI uri = new URI(value.trim());
|
||||
String scheme = uri.getScheme();
|
||||
return uri.getHost() != null && ("http".equalsIgnoreCase(scheme)
|
||||
|| "https".equalsIgnoreCase(scheme))
|
||||
? uri : null;
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAuthority(URI uri)
|
||||
{
|
||||
String host = uri.getHost();
|
||||
if (host == null) {
|
||||
return null;
|
||||
}
|
||||
if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
|
||||
host = "[" + host + "]";
|
||||
}
|
||||
return uri.getPort() > 0 ? host + ":" + uri.getPort() : host;
|
||||
}
|
||||
|
||||
private static boolean isInternalHost(String host)
|
||||
{
|
||||
if (isBlank(host)) {
|
||||
return true;
|
||||
}
|
||||
String normalized = host.trim().toLowerCase();
|
||||
if (normalized.startsWith("[") && normalized.contains("]")) {
|
||||
normalized = normalized.substring(1, normalized.indexOf(']'));
|
||||
} else if (normalized.indexOf(':') == normalized.lastIndexOf(':')) {
|
||||
normalized = normalized.substring(0, normalized.indexOf(':'));
|
||||
}
|
||||
return "localhost".equals(normalized)
|
||||
|| "127.0.0.1".equals(normalized)
|
||||
|| "0.0.0.0".equals(normalized)
|
||||
|| "::1".equals(normalized);
|
||||
}
|
||||
|
||||
private static String firstForwardedValue(String header, String name)
|
||||
{
|
||||
if (isBlank(header)) {
|
||||
|
||||
Reference in New Issue
Block a user