天天看點

SLB+Tomcat時request.RemoteAddr無法擷取正确的用戶端IP的問題解決方案

<b># 前情提要</b>

将cas部署到阿裡雲,使用slb進行前端負載以及ssl,後端使用tomcat作為應用伺服器。

按照正常方式部署上去之後,遇到如下問題:

1. ssl下使用redirect,自動跳轉到80端口。

2. cas無法擷取到用戶端的ip,cookies校驗出錯,導緻單點登入功能失效。

<b># 查找原因</b>

1. tomcat預設情況下的redirect會是80

2. cas的cookies檢查以及寫入程式使用request.getremoteaddr()擷取到的都是slb的ip,并非實際用戶端的ip,而且slb的ip不固定(貌似阿裡的slb是一個n多台機器的玩意,每次一個頁面請求過來,每個資源的請求ip都不同),我使用的杭州的slb,ip段在100.97.*.*這個範圍。

<b># 解決問題</b>

1. 設定tomcat的使用前端代理模式,解決tomcat中程式的redirect沒有跳轉到ssl的問題。

在server.xml中找到對外開放的connector,我的是用的nio-8080

&lt;connector port="8080"

  proxyname="這裡是域名"

  proxyport="443"

  scheme="https"

  secure="true"

  protocol="org.apache.coyote.http11.http11nioprotocol"

  connectiontimeout="20000" uriencoding="utf-8" usebodyencodingforuri="true"

  redirectport="8443" /&gt;

上述的含義是,

slb的域名是proxyname

slb對外端口是proxyport

slb使用的協定是https

slb是否開啟ssl:secure

2. 設定x-forwarded過濾器

在server.xml中的&lt;engine&gt;元素下增加如下内容:

&lt;valve classname="org.apache.catalina.valves.remoteipvalve"

  internalproxies="100\.97\.\d{1,3}\.\d{1,3}" /&gt;

internalproxies的意思是:tomcat僅接受這個ip段過來的請求中的x-forwarded系列的值覆寫為remote_addr等。加了這個過濾器之後使用request.getremoteaddr()就可以擷取到正确的用戶端ip了。需要注意的是,這個ip段需要根據你所用的slb來寫。

在tomcat裡,internalproxies的預設值為(無法覆寫到slb的ip段):

10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.1[6-9]{1}\.\d{1,3}\.\d{1,3}|172\.2[0-9]{1}\.\d{1,3}\.\d{1,3}|172\.3[0-1]{1}\.\d{1,3}\.\d{1,3} 

<b>特别注意:</b>

<b>這個&lt;value&gt;一定要寫在&lt;engine&gt;元素下!</b>

我查了很多網上的資料,都是說在server.xml裡面加上這個&lt;value&gt;,于是我看到tomcat有預設定義一個&lt;value&gt;在&lt;host&gt;裡面,于是我也跟着寫裡面,但是就是不生效。然後我特姆調試了兩天,結果一直不生效,最後在tomcat文檔裡找到這麼一句話:

this valve may be used at the <code>engine</code>, <code>host</code> or <code>context</code> level as required. normally, this valve would be used at the <code>engine</code> level.

其他參數請參考tomcat的文檔:

https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#remote_address_filter

希望此篇能給有需要的人帶來幫助。

繼續閱讀