经过反向代理Server如何优雅的获取用户IP

我们有一个对外提供rest接口的服务,为了限制权限,我们对访问接口的机器进行IP鉴权,只有合法的IP才允许访问,但由于服务端是一个集群,我们采用了自研的类似于nginx的反向代理服务对集群进行负载均衡,由于用户不是直接与我们服务端进行通信,而是经过代理层进行中转,我们直接获取访问IP获取到的是代理层的机器IP,因此如何获取到用户真实的访问IP非常关键。

我们采用的是SpringMVC+Spring+Hibernate框架,HttpServletRequest带有一个获取访问IP的方法:

String requestIp = request.getRemoteAddr()

这种方法只能获取到的是直接访问的IP,也就是说我们服务端采用这种方法获取到的是代理层的IP。

其实处理对于这种通过代理访问服务的方式获取IP的问题非常简单,只需要代理层将用户的IP放到request的header里面,然后我们获取对应的header值就可以了,但这不是我们今天讨论的重点,我们今天讨论的是如何在Java的服务端优化的获取这个header。

开始我想到的是封装一个工具类,里面封装好获取用户访问的真实IP:

上面截图的工具类我兼容了多种类型的header标识,服务中好多地方都用到了用户的IP(鉴权、日志记录等),用到的时候就调用这个工具类解析一下,倒也挺方便的,但对于我这种追求代码效率的人来说,简直不能忍,每次都要解析,感觉影响效率,还有优化的空间~

后来为了防止多次解析,我想到了另一种方式,就是配置一个Filter,将IP解析好了然后作为一个Attribute放入request里面:

然后什么地方用到IP就获取requestIp:

上面的方法能够避免每次都解析一遍,但是感觉代码太冗余,每次还得强制转型,Attribute的Key:requestIp还得约定好,对于我这种还追求代码优雅的程序猿来说,还是不能忍!!!

问题解决不了,吃也吃不好睡也睡不香,我当时想,如果我直接调用request.getRemoteAddr()就能获取到用户的真实IP该多方便呀,各种查资料,车到山前必有路,终于在一些技术网站找到了一些思路。主要的思想是继承HttpServletRequestWrapper重新封装HttpServletRequest,重写getRemoteAddr()方法,废话不多说,直接上代码:

然后继承Filter,写一个Servlet的拦截器:

最后将该拦截器配置到web.xml的第一个filter位置,对于SpringBoot如何配置拦截器请自行研究:

后续用到用户的真实IP就可以直接用request.getRemoteAddr()获取,也不用约定什么,是不是特别爽~~~

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180315G1UEJF00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券