开发者社区> 问答> 正文

SLBTomcat时request.RemoteAddr无法获取正确的客户端IP的问题解决方案

# 前情提要
将CAS部署到阿里云,使用SLB进行前端负载以及SSL,后端使用TOMCAT作为应用服务器。
按照常规方式部署上去之后,遇到如下问题:
1. SSL下使用redirect,自动跳转到80端口。
2. CAS无法获取到客户端的IP,Cookies校验出错,导致单点登录功能失效。


# 查找原因
1. TOMCAT默认情况下的redirect会是80
2. CAS的Cookies检查以及写入程序使用request.getRemoteAddr()获取到的都是SLB的IP,并非实际客户端的IP,而且SLB的IP不固定(貌似阿里的SLB是一个N多台机器的玩意,每次一个页面请求过来,每个资源的请求IP都不同),我使用的杭州的SLB,IP段在100.97.*.*这个范围。


# 解决问题
1. 设定TOMCAT的使用前端代理模式,解决TOMCAT中程序的redirect没有跳转到SSL的问题。
在server.xml中找到对外开放的Connector,我的是用的NIO-8080
<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" />
上述的含义是,
SLB的域名是proxyName
SLB对外端口是proxyPort
SLB使用的协议是https
SLB是否开启SSL:secure


2. 设定X-Forwarded过滤器
在server.xml中的<Engine>元素下增加如下内容:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
  internalProxies="100\.97\.\d{1,3}\.\d{1,3}" />
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}
特别注意:
这个<Value>一定要写在<Engine>元素下!
这个<Value>一定要写在<Engine>元素下!
这个<Value>一定要写在<Engine>元素下!
我查了很多网上的资料,都是说在server.xml里面加上这个<Value>,于是我看到Tomcat有默认定义一个<Value>在<Host>里面,于是我也跟着写里面,但是就是不生效。然后我特姆调试了两天,结果一直不生效,最后在TOMCAT文档里找到这么一句话:
This Valve may be used at the Engine, Host or Context level as required. Normally, this Valve would be used at the Engine level.



其他参数请参考Tomcat的文档:
https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Remote_Address_Filter



希望此篇能给有需要的人带来帮助。


展开
收起
花腩强 2016-05-18 11:19:27 6162 0
0 条回答
写回答
取消 提交回答
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载