7

当我尝试登录时,请求被Security组件黑洞。我怎样才能让它正常工作?

我有一个简单的登录表单

  <div class="container container-login">
    <h2><?php echo __('Login'); ?></h2>
    <div class="wrap-form-signin">
    <?php
    echo $this->Form->create('User', array('action' => 'login', 'class' => 'form-signin'));
    echo $this->Form->input('username', array('label' => '', 'placeholder' => __('Email')));
    echo $this->Form->input('password', array('label' => '', 'placeholder' => __('Password')));
    echo $this->Form->submit(__('Login'));
    echo $this->Form->end();
    ?>
    </div>
</div>

控制器动作如下:

public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                return $this->redirect($this->Auth->redirectUrl());             
            } else {
                $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
            }
        }
}

并且该Security组件包含在AppController

public $components = array('Security', ... );

在error.log中我得到:

2013-03-29 13:40:58 Error: [BadRequestException] The request has been black-holed
Request URL: /users/login
Stack Trace:
#0 C:\wamp\www\cdx\lib\Cake\Controller\Component\SecurityComponent.php(234): SecurityComponent->blackHole(Object(UsersController), 'auth')
#1 [internal function]: SecurityComponent->startup(Object(UsersController))
#2 C:\wamp\www\cdx\lib\Cake\Utility\ObjectCollection.php(131): call_user_func_array(Array, Array)
#3 [internal function]: ObjectCollection->trigger(Object(CakeEvent))
#4 C:\wamp\www\cdx\lib\Cake\Event\CakeEventManager.php(247): call_user_func(Array, Object(CakeEvent))
#5 C:\wamp\www\cdx\lib\Cake\Controller\Controller.php(670): CakeEventManager->dispatch(Object(CakeEvent))
#6 C:\wamp\www\cdx\lib\Cake\Routing\Dispatcher.php(183): Controller->startupProcess()
#7 C:\wamp\www\cdx\lib\Cake\Routing\Dispatcher.php(161): Dispatcher->_invoke(Object(UsersController), Object(CakeRequest), Object(CakeResponse))
#8 C:\wamp\www\cdx\app\webroot\index.php(92): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse))
#9 {main}

我怎样才能找到使我的请求进入黑洞的原因?

当我尝试使用自定义黑洞处理程序时,错误的类型是auth. 但这就是我能得到的所有信息

我的 CakePHP 版本是 2.3.1

编辑:登录在没有Security组件的情况下运行良好。将其添加到 后AppController,登录停止工作。

EDIT2:我在表格中没有任何data[_Token][key]字段

EDIT3 解决方案:我团队中的某个人已经覆盖了 HTMLHelper 类,并且它错过了 _tags 数组中的“hiddenblock”,导致缺少 _Token 字段。有关详细信息,请参阅我和 thaJeztah 的答案以及下面的评论

4

5 回答 5

5

您按什么顺序添加组件?安全组件应该放在其他处理表单数据的组件之前startup()

“如果您使用安全组件的表单保护功能和其他在启动()回调中处理表单数据的组件,请确保将安全组件放在 $components 数组中的这些组件之前。”

安全

因为 AuthComponent确实在 中处理表单数据startup(),所以我认为这适用,因此请确保 SecurityComponent在 $components 数组中的 AuthComponent之前;

public $components = array(
    'Security',
    'Session',
    'Auth' => array(
        // auth component settings
    )
);

更新

OP 发布的“最终”答案明确表明无法回答这个问题。事实证明,团队中的某个人对 HtmlHelper 进行了修改,导致它输出“隐藏”块,因此输出 CSRF 令牌。

在正常情况下,您永远不应该修改 CakePHP 框架文件本身。CakePHP 提供了在不修改“核心”CakePHP 文件的情况下覆盖其功能(包括 Helpers)的方法。

为什么修改 CakePHP 文件不好

例如,考虑一辆汽车。如果机械师不喜欢这种设计并决定“交换”刹车和油门踏板怎么办?

当然,如果您知道这种修改,汽车仍然可以行驶。但是,如果没有这些重要信息,任何其他驱动程序肯定会崩溃(并且想知道到底发生了什么!?

如果框架的默认行为不符合您的需要,请扩展这些类。不要自己修改框架文件(除非真的没有其他选择)。如果绝对有必要对框架进行修改,请务必与团队讨论这一点,并就所做的更改编写文档。

请记住,如果不对更新的版本进行相同的修改,就无法再将框架更新到较新的版本。同样,如果更改没有记录在案,有人可能会更新 CakePHP 并破坏您的修改。

此外,如果您覆盖或修改 CakePHP,请确保覆盖与 CakePHP 的默认行为兼容,并且 CakePHP 的单元测试仍然正确运行(或为修改创建新的单元测试)

在 CakePHP 中使用“自定义”助手

如果您需要自定义 CakePHP 助手(或其他组件),有多种选项可以在不修改 CakePHP 文件的情况下这样做;

1.扩展助手

class AwesomeHtmlHelper extends HtmlHelper {
    /**
     * enhanced tableHeaders method, outputs tableHeaders in a 'thead' tag
     *
     * {@inheritdoc}
     */
    public function tableHeaders(array $names, array $trOptions = null, array $thOptions = null)
    {
        $output = parent::tableHeaders($names, $trOptions, $thOptions);
        return '<thead>' . $output . '</thead>';
    }
}

然后,以常规方式使用您的 Helper:

echo $this->AwesomeHtml->tableHeaders(array('Date', 'Title', 'Active'));

2. 'Drop-in' 替换 - 使用别名 (CakePHP > 2.3)

从 CakePHP 2.3 开始,可以为 Helper 使用别名。此功能可用于(例如)您的应用程序中存在两个具有相同名称的 Helper(例如 Plugin.HtmlHelper)的情况。

此外,这允许您使用自己的 Helper 覆盖 CakePHP Helper。请参阅此处的文档:使用和配置助手

请注意,这将覆盖应用程序中任何地方的 Helper!

public $helpers = array(
    'Html' => array(
        'className' => 'AwesomeHtml'
    )
);

现在,$this->Html实际上将AwesomeHtmlHelper在您的意见中提及:

echo $this->eHtml->tableHeaders(array('Date', 'Title', 'Active'));

将输出您的“增强”表头

于 2013-03-31T22:27:19.957 回答
1

编辑:实际上没有错误

return $this->Html->useTag('hiddenblock', $out);

行,这是一个团队成员对HtmlHelper我不知道的修改,这阻止_Token了在页面中打印的输入。主要问题仍然存在,这是data[_Token][key]我必须添加的表单中没有输入


我终于发现了问题所在。由于课堂上可能出现错误,因此没有_Token字段FormHelper。我不得不编辑secure看起来像这样的方法:

public function secure($fields = array()) {
    if (!isset($this->request['_Token']) || 
            empty($this->request['_Token'])) {
        return;
    }
    $locked = array();
    $unlockedFields = $this->_unlockedFields;

    foreach ($fields as $key => $value) {
        if (!is_int($key)) {
            $locked[$key] = $value;
            unset($fields[$key]);
        }
    }

    sort($unlockedFields, SORT_STRING);
    sort($fields, SORT_STRING);
    ksort($locked, SORT_STRING);
    $fields += $locked;

    $locked = implode(array_keys($locked), '|');
    $unlocked = implode($unlockedFields, '|');
    $fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');

    $out = $this->hidden('_Token.fields', array(
        'value' => urlencode($fields . ':' . $locked),
        'id' => 'TokenFields' . mt_rand()
    ));
    $out .= $this->hidden('_Token.unlocked', array(
        'value' => urlencode($unlocked),
        'id' => 'TokenUnlocked' . mt_rand()
    ));
    return $this->Html->useTag('hiddenblock', $out);
}

此方法返回一个空字符串。因此,我没有返回结果,useTag而是简单地返回了$out.

我必须做的另一件事是添加该data[_Token][key]字段。最后,该方法如下所示:

public function secure($fields = array()) {
        if (!isset($this->request['_Token']) || 
                empty($this->request['_Token'])) {
            return;
        }
        $locked = array();
        $unlockedFields = $this->_unlockedFields;

        foreach ($fields as $key => $value) {
            if (!is_int($key)) {
                $locked[$key] = $value;
                unset($fields[$key]);
            }
        }

        sort($unlockedFields, SORT_STRING);
        sort($fields, SORT_STRING);
        ksort($locked, SORT_STRING);
        $fields += $locked;

        $locked = implode(array_keys($locked), '|');
        $unlocked = implode($unlockedFields, '|');
        $fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
        $key = $this->request['_Token']['key'];

        $out = $this->hidden('_Token.fields', array(
            'value' => urlencode($fields . ':' . $locked),
            'id' => 'TokenFields' . mt_rand()
        ));
        $out .= $this->hidden('_Token.key', array(
            'value' => $key,
            'id' => 'TokenKey' . mt_rand()
        ));
        $out .= $this->hidden('_Token.unlocked', array(
            'value' => urlencode($unlocked),
            'id' => 'TokenUnlocked' . mt_rand()
        ));
        return $out;
        //return $this->Html->useTag('hiddenblock', $out);
    }
于 2013-04-04T19:26:40.047 回答
0

很难使用您提供的信息进行测试,但我会尝试将表单创建调用更改为: echo $this->Form->create('User', array('url' => array('controller' => 'users', 'action' => 'login'), 'class' => 'form-signin'));

auth错误类型表示表单验证错误或控制器/操作不匹配错误。如果您显示表单的页面不是 NOT /users/login,则可能会发生这种情况,因为在使用安全组件时跨控制器通信是黑洞。希望能帮助到你

编辑:验证错误也可能表明您没有username为 Auth 组件定义结帐说明书

于 2013-03-31T12:57:54.323 回答
0

回答是因为我无法发表评论。您是否尝试过向 Security 组件添加回调并查看它到底生成了什么?

看:http ://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#handling-blackhole-callbacks

您究竟打算将安全组件用于什么目的?你想防止什么?

您是否尝试过使用会话令牌而不是表单令牌? http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#csrf-protection

public $components = array(
    'Security' => array(
        'csrfUseOnce' => false
    )
);
于 2013-04-01T16:01:57.450 回答
0

我对来自 login.ctp 的用户登录表单以及从另一个视图中将其用作元素都遇到了同样的问题,并设法通过使用 $this->Form->end() 关闭表单来解决此问题,否则它不会添加隐藏的输入形成令牌....希望这有帮助。

于 2014-05-20T17:29:38.100 回答