为公司的服务器加了一层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,
],
],