穿透多层代理获得真实ip

1. 使用微信支付时,有的手机ip获取不到外网ip,导致无法支付成功,提示:网络环境未能通过安全验证 请稍后再试

2. 之前使用的方法,只是粗略的,并不能适用所有情况,所有手机。

同时首先确保ngix代理访问api中做了相关配置,如:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

经过综合多种文章,最终实现了多层穿透代理获得真实ip的实现方法:

3. 代码贴上:

public class IPAddressUtils {
  /**
   * 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
   * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
   *
   *  获取终端ip(高配版)
   * @return ip
   */
  public static String getRealIpAddr(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    LOGGER.info("x-forwarded-for ip: {}", ip);
    if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
      //可能有代理
      if(ip.indexOf(".") == -1) {    //没有“.”肯定是非IPv4格式
        ip = null;
      } else {
        if (ip.indexOf(",") != -1) {
          //有“,”,估计多个代理。取第一个不是内网的IP。
          ip = ip.replace(" ", "").replace("'", "");
          String[] temparyip = ip.split(",|;");
          for (int i = 0; i < temparyip.length; i++) {
            if (isIPAddress(temparyip[i])  && ! isPrivateIp(temparyip[i])) {
              return temparyip[i];
            }
          }
        } else if(isIPAddress(ip)) { //代理即是IP格式
          return ip;
        } else {
          ip = null;     //代理中的内容 非IP,取IP
        }
      }
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("Proxy-Client-IP");
      LOGGER.info("Proxy-Client-IP: {}", ip);
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("WL-Proxy-Client-IP");
      LOGGER.info("WL-Proxy-Client-IP: {}", ip);
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("HTTP_CLIENT_IP");
      LOGGER.info("HTTP_CLIENT_IP: {}", ip);
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("HTTP_X_FORWARDED_FOR");
      LOGGER.info("HTTP_X_FORWARDED_FOR: {}", ip);
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("X-Real-IP");
      LOGGER.info("X-Real-IP: {}", ip);
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
      LOGGER.info("getRemoteAddr-IP: {}", ip);
    }
    LOGGER.info("=====获取客户端ip: {}", ip);
    return ip;
  }

  /**
   * 是否私有ip地址
   *
   * 在IPv4中,私有地址的范围分别是:
   * A类地址范围:10.0.0.0—10.255.255.255
   * B类地址范围:172.16.0.0---172.31.255.555
   * C类地址范围:192.168.0.0---192.168.255.255
   * @param tmpIp
   * @return
   */
  public static boolean isPrivateIp(String tmpIp) {
    LOGGER.info("isPrivateIp:{}", tmpIp);
    if(StringUtils.isBlank(tmpIp)) {
      return false;
    }
    if("10.".equals(tmpIp.substring(0, 3)) || "192.168".equals(tmpIp.substring(0, 7))) {
      return true;
    }
    if("172.".equals(tmpIp.substring(0, 4))) {
      String subStr = tmpIp.substring(4, 7);
      LOGGER.info("isPrivateIp-subStr:{}", subStr);
      Integer subNum = Integer.valueOf(tmpIp.substring(4, 6));
      LOGGER.info("isPrivateIp-subNum:{}", subNum);
      if(subStr.endsWith(".") && subNum > 15 && subNum < 32) {
        return true;
      }
    }
    return false;
  }


  public static boolean isIPAddress(String str1) {
    if(StringUtils.isBlank(str1) || str1.length() < 7 || str1.length() > 15) return false;
    String regformat = "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$";
    return str1.matches(regformat);
  }
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值