java后端获取客户端(用户)真实ip,原理

java后端获取客户端真实ip,原理:

一般都是下面代码中的做法:但很多人只知道这样能拿到,稍微有改动就不知道怎么办了
看看网上的各种说法,接下来容我一一讲解,如有纰漏,敬请指正。
public static String getIpAdrress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        System.out.println("====ipAddresses:"+ipAddresses);
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
        	//打印所有头信息
            String s = headerNames.nextElement();
            String header = request.getHeader(s);
            System.out.println(s+"::::"+header);
        }
        System.out.println("headerNames:"+JSON.toJSONString(headerNames));
        System.out.println("RemoteHost:"+request.getRemoteHost());
        System.out.println("RemoteAddr:"+request.getRemoteAddr());
        
        String unknown = "unknown";
        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

讲讲上面获取用户ip的代码

首先有个基本概念,就是客户端要想和服务端交互,就必须告诉服务端自己的ip,毕竟有TCP三次握手。
当然,这些都是普通用户,特殊用户会隐藏ip,这种暂且不说。
再从服务端说起,如果服务器直接把IP暴漏出去,那么request.getRemoteAddr()就能拿到客户端ip。

但目前流行的架构中,基本上服务器都不会直接把自己的ip暴漏出去,一般前面还有一层或多层反向代理,常见的nginx居多。
加了代理后,相当于服务器和客户端中间还有一层,这时候request.getRemoteAddr()拿到的就是代理服务器的ip了,并不是客户端的ip。所以这种情况下,一般会在转发头上加X-Forwarded-For等信息,用来跟踪原始客户端的ip。
这时候,才会用上面的这些代码。解释下这些加上的信息:

X-Forwarded-For:
这是一个 Squid 开发的字段,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。
格式为X-Forwarded-For:client1,proxy1,proxy2,一般情况下,第一个ip为客户端真实ip,后面的为经过的代理服务器ip。
上面的代码注释也说的很清楚,直接截取拿到第一个ip。
Proxy-Client-IP/WL- Proxy-Client-IP:
这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上Proxy-Client-IP请求头,
而WL-Proxy-Client-IP是他的weblogic插件加上的头。
这种情况也是直接能拿到。
HTTP_CLIENT_IP:
有些代理服务器也会加上此请求头。
X-Real-IP:
nginx一般用这个。

总结

不知道你有没有发现,上面这些头信息,都是各做各的,没有一个统一,所以代码也就写成了这样,其实就是一个一个试呗。

所以指不定以后再来个什么代理服务器,头信息是XX-xx-xx,那我们的代码也要做相应的修改。

还有,这代码只是一个大概的思想,具体情况具体对待,因为获取不到请求头这些ip的情况也不在少数,哪怕代理层以后都统一了,用户层还有其他幺蛾子方法,就是不让你知道他的ip,所以总的结论就是上有政策,下有对策。

举例几个常见的案例

1.服务端防刷
2.记录用户操作
等等,总之就是服务端监控和区分客户端的,经常会用ip作为一个可靠指标

你可能感兴趣的:(安全,java基础)