laravel获取nginx代理后的客户真实IP

问题:

用Laravel的$request->getClientIp()方法获取IP,

  1. 本机nginx proxy 获取到的是docker网络的Ip地址,类似172.17.0.1之流(docker创建的网络,本机的IP不是127.0.0.1)

  2. 另外一台机器用nginx proxy 获取到的是机器本身的外网IP

都无法获取客户的真实访问IP

原因:

查看laravel的getClientIp方法源码

public function getClientIps()
{
    $clientIps = array();
    $ip = $this->server->get('REMOTE_ADDR');

    if (!$this->isFromTrustedProxy()) {
        return array($ip);
    }

    $hasTrustedForwardedHeader = self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED]);
    $hasTrustedClientIpHeader = self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP]);

    if ($hasTrustedForwardedHeader) {
        $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
        preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
        $forwardedClientIps = $matches[3];

        $forwardedClientIps = $this->normalizeAndFilterClientIps($forwardedClientIps, $ip);
        $clientIps = $forwardedClientIps;
    }

    if ($hasTrustedClientIpHeader) {
        $xForwardedForClientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));

        $xForwardedForClientIps = $this->normalizeAndFilterClientIps($xForwardedForClientIps, $ip);
        $clientIps = $xForwardedForClientIps;
    }

    if ($hasTrustedForwardedHeader && $hasTrustedClientIpHeader && $forwardedClientIps !== $xForwardedForClientIps) {
        throw new ConflictingHeadersException('The request has both a trusted Forwarded header and a trusted Client IP header, conflicting with each other with regards to the originating IP addresses of the request. This is the result of a misconfiguration. You should either configure your proxy only to send one of these headers, or configure Symfony to distrust one of them.');
    }

    if (!$hasTrustedForwardedHeader && !$hasTrustedClientIpHeader) {
        return $this->normalizeAndFilterClientIps(array(), $ip);
    }

    return $clientIps;
}

1. remote_addr的值在经过proxy后变成了进行proxy的机器的ip,不再是客户真实的ip了;

2. isFromTrustedProxy判断了proxy的remote_addr,要把remote_addr写入白名单;

3. 经过proxy的ip获取的是X-Forwarded-For的值;

解决办法:

  1. nginx设置X-Forwarded-For
server {
        listen 80;
        server_name  www.XXXXX.cn;
        location / {
            proxy_pass http://XX.XX.XX.XX;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}
  1. laravel添加TrustedProxy

通过Request::setTrustedProxies()方法设置;传入ip数组

可以是掩码的格式,例如:

[
    "172.17.0.1/16",
    "156.132.44.23"
]
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容