3

由于我们设置 AWS 托管的方式,我必须为 CakePHP 的 loginAction 使用绝对 URL。目前,我的 loginAction 看起来像这样(现在不起作用)

'loginAction' => array('controller' => 'users', 'action' => 'login'),

将它与来自 HTTP -> HTTPS 的重定向结合起来,我得到一个重定向循环。我可以通过设置这样的绝对 URL 来证明这一点(工作正常)

'loginAction' => array('https://foo.com'),

我以为我可以像这样将最终参数设置为 true

'loginAction' => array('controller' => 'users', 'action' => 'login', TRUE),

但这也不起作用。

我最后的失败我尝试设置这样的东西,

'loginAction' => "https://{$_SERVER['HTTP_HOST']}/users/login",

这引发了一个完全不相关的错误 - PHP Parse error: syntax error, unexpected '"'

所以我的问题是,

  • 我可以在 loginAction() 中设置绝对 URL
  • 或者,我可以告诉 Cake 始终使用绝对 URL,例如 routes.php 或 bootstrap.php?

我见过人们谈论 FULL_BASE_URL 和其他常量,但似乎没有任何帮助。

4

1 回答 1

4

这正是我们最近在设置 AWS Elastic Beanstalk 时遇到的问题。问题是,当负载均衡器访问您的实例时,它实际上使用 PORT 80 (http),如果您密切关注流程:

  1. AuthComponent用来$controller->redirect()做 loginRedirect [ AuthComponent::419 ]
  2. redirect()用于Router::url($loginRedirect, true)获取完整的 url。[控制器::774 ]
  3. Router::url()用于Router::fullBaseUrl()解析完整的基本 url [ Router::899 ]
  4. Router::fullBaseUrl()用于Configure::read('App.fullBaseUrl')读取写入的完整基本 url。[路由器::929 ]

那么问题来了,谁解决了fullBaseUrl

进一步挖掘,你会看到Cake\bootstrap.php,[罪魁祸首在该文件的第 158 行

if (!defined('FULL_BASE_URL')) {
    $s = null;
    if (env('HTTPS')) { <---------------- @@@@ env('HTTPS') is false!!!! @@@@
        $s = 's';
    }

    $httpHost = env('HTTP_HOST');

    if (isset($httpHost)) {
        define('FULL_BASE_URL', 'http' . $s . '://' . $httpHost);
        Configure::write('App.fullBaseUrl', FULL_BASE_URL);
    }
    unset($httpHost, $s);
}

知道了?AWS 负载均衡器会在端口 80 上访问您的实例,而不会告诉您这是一个 https 调用(以通常的方式),因此 cake 被误认为它是 http,因此会导致重定向循环。

我们的解决方案相当老套。由于我们使用的是弹性 beanstalk 并且我们可以编辑环境变量,我们在我们的.config文件中执行此操作.ebextensions

option_settings:
  - option_name: HTTPS
    value: 1

当我们根本不想要 http(并且总是强制重定向使用 https)时,这很好。但更好的是,也许使用HTTP_X_FORWARDED_*变量来确定环境(如果你仍然需要http):

如果你debug($_SERVER),你应该能够看到这样的东西:

["HTTP_X_FORWARDED_FOR"]=>"xx.xx.xx.xx, xx.xx.xx.xx, ...." //note that the first is IP, the rest are proxies
["HTTP_X_FORWARDED_PORT"]=>"443"
["HTTP_X_FORWARDED_PROTO"]=>"https"

所以这让你只有一个选择:编辑你的bootstrap.php并在顶部添加这一行:

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

一旦它尝试解析完整的基本 URL,您将获得正确的协议集。

(或者,define('FULL_BASE_URL'..)如果你愿意,你可以,但我不喜欢它:p)

笔记

当我们第一次进入这个负载平衡世界时,一切都略有不同。如果您的代码的任何部分没有表现出应有的行为,请始终检查$_SERVER数组。例如,你不应该再依赖$_SERVER['REMOTE_ADDR']了。您需要从中分解并检测此变量$_SERVER['HTTP_X_FORWARDED_FOR']

编辑

如果安全是一个问题,请查看此线程。上面的黑客可能很方便,但不是防弹:https ://github.com/cakephp/cakephp/issues/2035




2013 年 9 月 15 日基于 CakePHP 2.4.1 的回答,提交085636ea1bb2a57b084456e776bfada01dee71df

于 2013-09-15T12:45:21.397 回答