如果透过Nginx获取客户端ip

树荫下的天空 发布于 2017/11/10 22:52
阅读 786
收藏 1

google非常久都找不到答案,无奈才来这边提问.

网上搜到的结果基本上都是什么通过X-Forwarded-For,X-Real-IP.我测试都是获取到127.0.0.1(不是本地访问,是ngrok后用手机访问的,所以这个地址肯定是错误的)

代码如下
/**获取ip工具类 */
public class IpUtil {

    /**
     * 穿透反向代理服务器,获取ip地址
     *
     * @param request
     * @return
     */
    public static String getIpThroughProxy(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }

    /**
     * 获取客户端IP,支持反向代理,如nginx,但不支持正向代理,比如客户端浏览器自己使用代理工具
     * @param request
     * @return 客户端IP
     */
    public static String getClientIP(HttpServletRequest request)
    {
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getRemoteAddr();
        return ip;
    }

}

Controller类:

@Controller
public class IndexController {

    @GetMapping("/test")
    @ResponseBody
    @RequiresGuest
    public String hello(HttpServletRequest request) {
        String ip1 = IpUtil.getClientIP(request);
        String ip2 = IpUtil.getIpThroughProxy(request);
        System.out.printf("ip1 = %s.ip2 = %s",ip1,ip2);
        return ip1;
    }
}

Nginx.conf配置文件:
server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass   http://WeChat;
    proxy_redirect off;

            proxy_set_header Host $host;

            proxy_set_header X-Real-IP $remote_addr;

    proxy_set_header REMOTE-HOST $remote_addr;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        }
    }

    upstream WeChat {
server 127.0.0.1:8080;
    }
结果
输出ip1 和ip2都是127.0.0.1

 

加载中
1
TavenLi
TavenLi

其实呢,你的问题出在你只是照抄网络,而没有认真去理解这个里面的原理。

因为你的应用被反向代理了后,真实用户是跟反向代理Nginx交互的,然后Nginx跟你的真实应用进行交互,这个时候,你的应用程序是不知道外面的真实用户的,所以你需要让Nginx把真实用户的IP传给你的后端真实应用,proxy_set_header X-Forwarded-For $remote_addr 这句就是把Nginx获取到的真实IP($remote_addr) 写到头里面,名为X-Forwarded-For,然后你的真实用户只要去取HTTP头里面的 X-Forwarded-For 属性就可以了。其实,你nginx里面,X-Forwarded-For 和 X-Real-IP 只要设其中一条就可以了,多了反而出问题,为什么呢?

你的问题就出在顺序上,你设的

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这个是有问题的

proxy_set_header X-Real-IP $remote_addr;  这个是对的

最糟糕的是,你java代码里面又优先取得是 X-Forwarded-For 变量,这样就不会再去取 X-Real-IP 的值了。所以你复制来一堆代码,取得还是不对。

 

 

 

 

0
树荫下的天空
树荫下的天空

这个问题困扰我非常久,我又把Nginx关闭,直接访问tomcat,就能获取客户端ip了.问题还是在Nginx上

0
公孙二狗
公孙二狗

server_name  localhost;

这个配置好像不对,应该是一个域名

0
树荫下的天空
树荫下的天空

引用来自“公孙二狗”的评论

server_name  localhost;

这个配置好像不对,应该是一个域名

我把他改成ngrok提供的域名,效果也一样

0
公孙二狗
公孙二狗
    /**
     * 获取客户端的 IP
     * @param request
     * @return 客户端的 IP
     */
    public static String getClientIp(HttpServletRequest request) {
        final String UNKNOWN = "unknown";
        // 需要注意有多个 Proxy 的情况: X-Forwarded-For: client, proxy1, proxy2
        // 没有最近的 Proxy 的 IP, 只有 1 个 Proxy 时是客户端的 IP
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr(); // 没有使用 Proxy 时是客户端的 IP, 使用 Proxy 时是最近的 Proxy 的 IP
        }
        return ip;
    }

下面是 OpenResty(Nginx) 的配置,前几天还在用,可以取到 IP

    server {
        listen       80;
        server_name  www.xtuer.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_redirect   off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://app_server;
        }

 

0
ddatsh
ddatsh

为什么我看到 标题里不正确的如果是如此的来气

0
树荫下的天空
树荫下的天空

引用来自“公孙二狗”的评论

    /**
     * 获取客户端的 IP
     * @param request
     * @return 客户端的 IP
     */
    public static String getClientIp(HttpServletRequest request) {
        final String UNKNOWN = "unknown";
        // 需要注意有多个 Proxy 的情况: X-Forwarded-For: client, proxy1, proxy2
        // 没有最近的 Proxy 的 IP, 只有 1 个 Proxy 时是客户端的 IP
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr(); // 没有使用 Proxy 时是客户端的 IP, 使用 Proxy 时是最近的 Proxy 的 IP
        }
        return ip;
    }

下面是 OpenResty(Nginx) 的配置,前几天还在用,可以取到 IP

    server {
        listen       80;
        server_name  www.xtuer.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_redirect   off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://app_server;
        }

 

心好累  我的配置和你一模一样,就是强行返回127.0.0.1,哥们你Nginx版本多少

树荫下的天空
树荫下的天空
回复 @公孙二狗 : 心累 不知道问题在哪
公孙二狗
公孙二狗
nginx version: openresty/1.11.2.5
0
TavenLi
TavenLi

Nginx的配置改成如下即可:

        location / {
            proxy_redirect   off;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;            
            proxy_pass http://app_server;
        }
 

注意顺序哦!

 

 

0
树荫下的天空
树荫下的天空

引用来自“TavenLi”的评论

其实呢,你的问题出在你只是照抄网络,而没有认真去理解这个里面的原理。

因为你的应用被反向代理了后,真实用户是跟反向代理Nginx交互的,然后Nginx跟你的真实应用进行交互,这个时候,你的应用程序是不知道外面的真实用户的,所以你需要让Nginx把真实用户的IP传给你的后端真实应用,proxy_set_header X-Forwarded-For $remote_addr 这句就是把Nginx获取到的真实IP($remote_addr) 写到头里面,名为X-Forwarded-For,然后你的真实用户只要去取HTTP头里面的 X-Forwarded-For 属性就可以了。其实,你nginx里面,X-Forwarded-For 和 X-Real-IP 只要设其中一条就可以了,多了反而出问题,为什么呢?

你的问题就出在顺序上,你设的

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这个是有问题的

proxy_set_header X-Real-IP $remote_addr;  这个是对的

最糟糕的是,你java代码里面又优先取得是 X-Forwarded-For 变量,这样就不会再去取 X-Real-IP 的值了。所以你复制来一堆代码,取得还是不对。

 

 

 

 

还是不行哦老哥

这次我 配置完全听你的了,还是都获取到127.0.0.1.

我之前试过直接获取 X-Real-IP头获取不到,网上说这样行不通我才又改成别人的代码(贴子上展示的这套).

还是感谢你抽空回答

0
TavenLi
TavenLi

在你java代码里面设断点,看看:

String ip = request.getHeader("X-Forwarded-For");

上面这行代码取到的是什么,如果是空的,就核对一下字符串名字是否设置对了,否则不可能错,或者把nginx配置改成如下试试:

		location / {
			proxy_pass http://app_server;
			proxy_set_header Host $http_host;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
			proxy_set_header X-Real-IP $remote_addr; 
			proxy_set_header REMOTE_ADDR $remote_addr;
		}

 

返回顶部
顶部