目標:request.getRemoteAddr()在 Spring Boot Web 應用程式中獲取用戶(即)的遠程地址。
簡介:眾所周知,該getRemoteAddr方法回傳直接呼叫者的地址,該呼叫者可能是代理服務器或原始用戶和最終目標服務器(如果有)之間的任何其他服務器。要找到用戶的真實地址,需要查看其他標題(例如X-Forwarded-For)。但是我發現 Tomcat(它是我們的 Web 容器)有一個過濾器RemoteIpFilter,它通過復制存盤在另一個標頭(例如X-Forwarded-For)中的原始地址來解決這個問題,以便呼叫request.getRemoteAddr()為您提供原始地址。
我將過濾器添加到代碼中,一切正常:
@Bean
FilterRegistrationBean<RemoteIpFilter> remoteIpFilter() {
val filter = new FilterRegistrationBean<>(new RemoteIpFilter());
filter.addUrlPatterns("/*");
return filter;
}
然而,有一個問題;當請求是多部分請求時,Spring 拒絕它:
The request was rejected because the header value "multipart/mixed; boundary="----=_Part_0_blahblah"; charset=utf-8" is not allowed.
我可以看到拋出例外是因為FilterChainProxySpring 的過濾器StrictFirewalledRequest依次包裝了請求,對允許和不允許的內容進行了一些檢查(例如,上面的內容型別是不允許的)。
除了將RemoteIpFilter過濾FilterChainProxy器放在過濾器之前,我找不到上述問題的合適解決方案:
// right before the tracing filter!
filter.setOrder(SleuthWebProperties.TRACING_FILTER_ORDER - 1);
問題
- 使用
RemoteIpFilter是個好主意嗎? - 有沒有更好的方法來解決上述問題?
- 什么是最好的訂單號
RemoteIpFilter?
謝謝。
uj5u.com熱心網友回復:
感謝 Piotr P. Karwasz 的評論,我想出了如何做到這一點。這并不簡單,因為它取決于環境和其他組件(例如 LB、反向代理等)。但這就是你要做的:
- 不要使用
RemoteIpFilter,如果你使用Spring引導 Tomcat的的最新版本。如果需要,Spring Boot 通過創建RemoteIpValue(inTomcatWebServerFactoryCustomizer) 來滿足您的需求。 - 如果您在某個云平臺上進行部署,那么您可能不需要做任何事情,因為如果 Spring 檢測到該平臺為云平臺,它會自動創造價值。無需明確告訴它。(看看什么
CloudPlatform.getActive(env)回傳。) - 如果您不是在云平臺上部署,則可能需要至少設定以下屬性之一:
ServerProperties#forwardHeadersStrategy = NATIVE(正如 Piotr 建議的那樣)ServerProperties.Tomcat.Remoteip#protocolHeader(對任何東西,例如X-Forwarded-Proto)ServerProperties.Tomcat.Remoteip#remoteIpHeader(對任何東西,例如X-Forwarded-For)
- 要查看它是否真的有效,請啟用除錯日志
org.apache.catalina.valves.RemoteIpValve,您應該能夠查看有關更改主機、地址等的日志。
在我們的例子中,我不需要在 Spring 上做任何事情,因為我們將我們的應用程式部署到 K8S,Spring 在 K8S 上創建了閥門。那為什么我沒有得到正確的遠程地址呢?事實證明,我們的反向代理 Nginx 具有默認配置:
proxy_set_header X-Forwarded-For $remote_addr;
這基本上覆寫了原始值,即由RemoteIpValve用于設定遠程地址。換句話說,閥門正確讀取了X-Forwarded-For標題,但標題不包含正確的值(用戶的地址)。請注意,這$remote_addr不一定是用戶的地址。它可能是其他一些中間代理/LB 的地址。
所以你有兩個選擇來解決這個問題:
- 設定
ServerProperties.Tomcat.Remoteip#remoteIpHeader為X-Original-Forwarded-For因為這是 NginxX-Forwarded-For在用 覆寫之前備份 的原始值的地方$remote_addr。(對我來說似乎是一個黑客!) - 將 Nginx 配置為根本不觸摸
X-Forwarded-For標頭。(對我來說似乎是一個黑客!) - 將 Nginx 配置為追加
X-Forwarded-For而不是覆寫它。
要將 Nginx 配置為追加,您有兩個選擇:
- 處理這樣的事情
proxy_set_header X-Forwarded-For "$remote_addr, $server_addr"并將 Nginx 配置為追加而不是覆寫。(有關如何在 K8S 上執行此操作,請參閱此內容。雖然我無法使其正常作業;Nginx 抱怨引數的數量proxy-set-header或類似問題。另外,我不確定它是否是防彈解決方案) - 配置 Helm chart 安裝值:
config:
"use-forwarded-headers": "true" # not true
"compute-full-forwarded-for": "true" # not true
感謝 Piotr 的提示:)
PS:關于新的花哨標題還有一些其他說明Forwarded應該解決整個混亂,但顯然 Nginx 還沒有完全支持它。
PSS:我沒有花時間弄清楚為什么拋出例外或如何防止它。那可能是另一天:)
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316740.html
