Yii2在有代理时获取客户端真实IP

yii2 nginx Yii2 · qingqing · 于 3年前 发布 · 1673 次阅读

项目场景:

为公司的服务器加了一层Nginx反向代理之后,Yii::$app->request->userIP无法得到真实的客户IP。

问题描述:

Yii::$app->request->userIP无法得到客户真实IP这种情况下,会造成一下PHP定位失败、日志追踪错误的问题。对于维护系统有很大的麻烦。 而自己看到Yii::$app->request->userIP得到的是代理服务器的ip,还以为在代理服务器的Nginx上面的并没有把客户的真实ip进行转发。 检查Nginx配置之后发现 X-Real-IP 和 X-Forwarded-For 已经配置成功。

location /{
        proxy_pass $remoteHostIp;
        proxy_http_version 1.1;
        proxy_connect_timeout 10s;
        proxy_read_timeout 300s;
        proxy_send_timeout 600s;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host "www.test.com";
    }

然后再去做了一个临时页面,把$_SERVER变量打印出来。

于是,直接阅读 yii\web\Request 的代码,其中关于headers有这样的一个方法

public function getHeaders()
    {
        if ($this->_headers === null) {
            $this->_headers = new HeaderCollection();
            if (function_exists('getallheaders')) {
                $headers = getallheaders();
                foreach ($headers as $name => $value) {
                    $this->_headers->add($name, $value);
                }
            } elseif (function_exists('http_get_request_headers')) {
                $headers = http_get_request_headers();
                foreach ($headers as $name => $value) {
                    $this->_headers->add($name, $value);
                }
            } else {
                foreach ($_SERVER as $name => $value) {
                    if (strncmp($name, 'HTTP_', 5) === 0) {
                        $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
                        $this->_headers->add($name, $value);
                    }
                }
            }
            $this->filterHeaders($this->_headers);
        }

        return $this->_headers;
    }

    protected function filterHeaders(HeaderCollection $headerCollection)
    {
        // do not trust any of the [[secureHeaders]] by default
        $trustedHeaders = [];

        // check if the client is a trusted host
        if (!empty($this->trustedHosts)) {
            $validator = $this->getIpValidator();
            $ip = $this->getRemoteIP();
            foreach ($this->trustedHosts as $cidr => $headers) {
                if (!is_array($headers)) {
                    $cidr = $headers;
                    $headers = $this->secureHeaders;
                }
                $validator->setRanges($cidr);
                if ($validator->validate($ip)) {
                    $trustedHeaders = $headers;
                    break;
                }
            }
        }

        // filter all secure headers unless they are trusted
        foreach ($this->secureHeaders as $secureHeader) {
            if (!in_array($secureHeader, $trustedHeaders)) {
                $headerCollection->remove($secureHeader);
            }
        }
    }

当HTTP_X_FORWARDED_FOR作为编一个数组[“X-Forwarded-For” => “192.168.99.100”]被保存在之后,在经过安装过滤 filterHeaders() 函数时,由于定制服务器的IP并不在 $this->trustedHosts 中,所以,被执行remove操作。导致最后没有读取到代理服务器传递过来的客户端真实IP。

解决方案:

所以只需要在 yii\web\Request 的属性 $trustedHosts 增加上代理服务器IP即可。本来想自己包里插入数据。最后还是看到了官方文档

'request' => [
    'trustedHosts' => [
        '127.0.0.1,
    ],
],
共收到 0 条回复
没有找到数据。
添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册