强制https时重定向symfony2中的循环


Redirect Loop in symfony2 when forcing https

在我的Symfony2应用程序中,我设置了一个防火墙,以便/admin路由下的所有内容都需要通过https运行,但在部署时,我会得到一个重定向循环。我已经阅读了Symfony2网站上关于防火墙的文档,并设置了登录表单。我还阅读了一些Stack Overflow文章,并尝试了他们的解决方案,但到目前为止还没有。

下面是我的配置,是不是缺少什么?

(据我所知,服务器正在运行Apache,我无法从我的托管提供商直接访问服务器配置)

access_control:
    # require ROLE_ADMIN for /admin*
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
    - { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
    - { path: ^/admin*, roles: ROLE_ADMIN, requires_channel: https}

更新:修复了该问题。事实证明,一些服务器变量没有在宿主提供程序上设置。

为了将来参考,请在web或public_html目录的app.php下添加以下内容。可能是一个肮脏的黑客,但它为我解决了问题。

if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
{ 
  $_SERVER['HTTPS'] = 'on';
  $_SERVER['SERVER_PORT'] = 443;
}

根据您自己的答案,您的网站似乎落后于负载均衡器或反向代理(因为您需要检查HTTP_X_FORWARDED_PROTO服务器变量,该变量通常为空)。

您的托管提供商可能在您不知情的情况下设置了这样的设置。默认情况下,Symfony会忽略X-Forwarded-ProtoX-Forwarded-For标头,除非您将代理添加到app/config/config.yml文件的白名单中:

framework:
    trusted_proxies:  [127.0.0.1, ::1]

其中127.0.0.1::1应替换为托管提供商使用的实际代理(他们应该能够告诉您)。

这样做应该可以让它在不侵入app.php文件的情况下工作。

根据@Oldskool的正确答案,在SF>3.3上,您可以使用env变量在SF4中设置trusted_proxies,因为该节点已从该版本删除。

在Symfony>3.2<4,代码如下:

# web/app.php
// BEFORE
// ...
$kernel = new AppKernel('prod', false);
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null);
$request = Request::createFromGlobals();
// ...
// AFTER
// ...
$kernel = new AppKernel('prod', false);
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null);
Request::setTrustedProxies(['192.0.0.1', '10.0.0.0/8']);
$request = Request::createFromGlobals();
// ...

如果使用SF4,则可以使用env变量作为前控制器(在public/index.php中)读取它们。

因此,只需添加env变量TRUSTED_PROXIES,将其放入所有受信任的代理中,用逗号","分隔:

TRUSTED_PROXIES = xxx.xxx.xxx.xxx/x,xxx.xxx.xxx.xxx/x,xxx.xxx.xxx.xxx/x

作为最后的参考,您可以在GitHub上查看强制https导致的无限循环的问题。

HEROKU

作为一个简单的参考,因为我在Heroku上遇到了这个问题

如果你在强制使用https时遇到问题,并且你的应用程序在Heroku:上

您必须遵循Heroku提供的说明(仅适用于SF<=3.2):

// web/app.php
Request::setTrustedProxies(array($request->server->get('REMOTE_ADDR')));
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null);
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null);

对于Symfony>3.2(此处针对SF4的说明):

// SF >= 4: public/index.php
...
$kernel = new Kernel($env, $debug);
$request = Request::createFromGlobals();
// Add this
Request::setTrustedProxies(array($request->server->get('REMOTE_ADDR')), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
$response = $kernel->handle($request);
...