【问题标题】:'_Token' was not found in request data in CakePHP3 after server migration服务器迁移后,在 CakePHP3 的请求数据中未找到“_Token”
【发布时间】:2016-09-18 13:09:11
【问题描述】:

编辑:

在提出这个问题后获得的一系列新见解告诉我问题是什么,而且它绝对与所描述的服务器迁移没有任何关系。

给出的两个答案显示了如何为 CakePHP 2 和 3 “修复”此问题,但请记住,这可能会带来安全风险。 CSRF 组件是一项重要的安全功能,不应轻易禁用。

原问题:

我将我的 CakePHP 3 项目从笔记本电脑上的 XAMPP 迁移到服务器上的 XAMPP。自从我激活安全组件时,蛋糕给我一个错误。在这里,直接来自错误日志:

    2016-05-21 20:32:01 Error: [Cake\Controller\Exception\AuthSecurityException] '_Token' was not found in request data.
Request URL: /Users/addUser
Referer URL: http://localhost/users/add_user
Stack Trace:
#0 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Controller\Component\SecurityComponent.php(324): Cake\Controller\Component\SecurityComponent->_validToken(Object(App\Controller\UsersController))
#1 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Controller\Component\SecurityComponent.php(130): Cake\Controller\Component\SecurityComponent->_validatePost(Object(App\Controller\UsersController))
#2 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Event\EventManager.php(386): Cake\Controller\Component\SecurityComponent->startup(Object(Cake\Event\Event))
#3 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Event\EventManager.php(356): Cake\Event\EventManager->_callListener(Array, Object(Cake\Event\Event))
#4 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Event\EventDispatcherTrait.php(78): Cake\Event\EventManager->dispatch(Object(Cake\Event\Event))
#5 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Controller\Controller.php(495): Cake\Controller\Controller->dispatchEvent('Controller.star...')
#6 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Routing\Dispatcher.php(109): Cake\Controller\Controller->startupProcess()
#7 C:\xampp\htdocs\vendor\cakephp\cakephp\src\Routing\Dispatcher.php(87): Cake\Routing\Dispatcher->_invoke(Object(App\Controller\UsersController))
#8 C:\xampp\htdocs\webroot\index.php(37): Cake\Routing\Dispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response))
#9 {main}

我在 StackOverflow 上找到了 CakePHP security component blackholing login (data[_Token][key] field not generated),但没有其他有关导致我的问题的相关信息。在我的应用控制器中:

    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Security');
        $this->loadComponent('RequestHandler');
        $this->loadComponent('Flash');

【问题讨论】:

    标签: php cakephp


    【解决方案1】:

    更新:另外,请确保您没有忘记echo $this->Form->end();,因为它添加了所有必要的令牌。原始答案如下。

    更新:您在提交表单created separately via new \Cake\View\ViewBuilder()时也可能遇到这个问题


    正确的答案确实是花一些时间来更新您的代码,使其符合安全组件指南。禁用组件或解锁特定操作是一种解决方法,而不是解决方案。

    关于_Token 的一些不太明显的事情。

    先决条件:我有一个占位符 <form> 用于构建重复的、几乎相同的 AJAX 请求(一个字段在 javascript 循环中不断更新并重新提交;不要问为什么) .

    • _Token 链接到表单操作 URL。你不能让你的占位符表单指向例如javascript:; 并有实际请求,用它的令牌签名,转到其他端点

    • _Token 可重复使用。可以发出多个使用相同令牌签名的请求(即一遍又一遍地提交相同的表单),这不是我想的一次性令牌

    所以我所做的是将我的不同信息放入type="text" 输入和display:none 它,而不是使用type="hidden" 输入,这将属于防止表单篡改。然后我将serialize()'d 表单放入jQuery.ajax() 数据属性中。

    // update the CSS-hidden type="text" input
    document.forms.exampleForm.quantity.value=newValue;
    // submit the form
    jQuery.ajax({
        url: document.forms.exampleForm.action,
        type: document.forms.exampleForm.method,
        data: jQuery(document.forms.exampleForm).serialize(),
        complete: function(jqXHR) {
            //
        }
    });
    

    当然可以采取简单的unlockedActions 路线,但如果您不这样做,您可能会很高兴。

    【讨论】:

    【解决方案2】:

    该错误与_TOKEN 有关。当我们创建一个 CakePHP 表单,然后根据输入字段,CakePHP 会生成名为 _TOKEN 的隐藏字段。

    例如:

    <?= $this->Form->create(false, [
        'id' => "ajaxForm",
        'url' => [
            'controller' => 'TPCalls', 
            'action' => 'add'
        ],
        'class'=> "addUpdateDeleteEventForm"
        ]); 
    ?>
    <?= $this->Form->input('id', ['label' => false]); ?>
    <?= $this->Form->input('start', ['label' => false]); ?>
    <?= $this->Form->input('end', ['label' => false]); ?>
    <?= $this->Form->input('title', ['label' => false]); ?>
    <?= $this->Form->hidden('ADD', ['value' => 'true']); ?>
    <?= $this->Form->end(); ?>
    

    现在您应该在检查 HTML 时在表单中看到 _TOKEN 值:

    <input type="hidden" name="_Token[fields]" autocomplete="off" value="---HASH---">
    

    如果您没有任何可见字段,则 _Token 将为空。如果您需要有不可见的字段,那么只需在表单或字段上添加一个隐藏类。

    无论如何,回到主要问题。该错误是由_TOKEN 字段的缺失引起的。在上述情况下,我会在进行 Ajax 调用之前序列化我的表单。

        //serializing the form    
        var ajaxdata = $("#ajaxForm").serializeArray();
    
        //ajax
        $.ajax({
            url:$("#ajaxForm").attr("action"),
            type:"POST",
            beforeSend: function(xhr){
                xhr.setRequestHeader("X-CSRF-Token", $('[name="_csrfToken"]').val());
            },
            data:ajaxdata,
            dataType: "json",
            success:function(response) {
                console.log(response);
            },
            error: function(response) {
                console.error(response.message, response.title);
            }
        });
    

    请注意,在 ajax 中,我使用的是 Cakephp 表单中的 URL,而不是在 ajax 中对其进行硬编码。这样,它将使用 cakephp url helper。

    【讨论】:

    • 我也遇到这个问题,在(Cakephp源码)[github.com/cakephp/cakephp/blob/3.7.4/src/Controller/Component/….我发现您的解决方案与我在以下方面的实现不同:1. 不需要xhr.setRequestHeader("X-CSRF-Token", $('[name="_csrfToken"]').val()); 2.var ajaxdata = $("#ajaxForm").serializeArray(); 可能需要像var ajaxdata={}; $.each($('#ajaxForm').serializeArray(), function() {ajaxdata[this.name] = this.value;}); 那样进行进一步处理
    【解决方案3】:

    @Invincible 的回答很好,但以这种方式应用 csrf 似乎是应用和维护的噩梦,因为我们的应用程序中已经有大约 20 个左右的 Ajax。

    所以我使用Cakephp 3 - element 来帮助抽象一些代码。如果您还想抽象 csrf 令牌,我将我的代码粘贴在这里供其他人参考。

    代码如下:

    元素:csrf_ajax_element.ctp

    <?= 
        $this->Form->create(false, [ 
            "id" => $name . "Form",
            "url" => $url,
        ]); 
    ?>
    
    <? if(isset($params)): ?>
        <? foreach($params as $param) : ?>
        <?= $this->Form->input($param, ['label' => false, 'style' => 'display:none;']); ?>
        <? endforeach; ?>
    <? endif; ?>
    <?= $this->Form->end(); ?>
    
    <script type="text/javascript">
        var csrfName = '<?=$name?>';
        var url = '<?= $this->Url->build($url) ?>';
        var csrf = { };
        $.each($('#'+csrfName+'Form').serializeArray(), function() {csrf[this.name] = this.value;});
    
        $("#"+csrfName).data('csrf', csrf);
        $("#"+csrfName).data('url', url);
    </script>
    

    要在页面上添加 ajax,请执行以下操作:

    some_page.ctp

    <!-- At the top -->
    
    <input id="myAjaxCsrfToken" type="hidden" data-csrf="" data-url="" />
    
    <?= $this->element('csrf_ajax_element', 
        [
            "name" => "myAjaxCsrfToken", 
            "params" => ['year'],
            "url" => ["controller" => "Api", "action" => "myAjax", "_method" => "POST" ]
        ]) 
    ?>
    
    <!-- When you need to use the ajax -->
    <script type="text/javascript">
    $.ajax({
        url: $("#myAjaxCsrfToken").data('url'),
        type: 'POST',
        data: $.extend(
            $("#myAjaxCsrfToken").data('csrf'), 
            { year: 2019 }
        ),
        complete: function() {
            // things
        }
    });
    </script>
    

    注意:上面year是一个自定义参数,需要和token参数一起传递给ajax,如果不这样做,cakephp会输出安全错误。

    【讨论】:

      【解决方案4】:

      编辑@Invincible 评论后

      禁用 csrf 和安全组件时要小心,它们可以防止 csrf 和表单篡改、强制 ssl、http 方法等 https://book.cakephp.org/3.0/en/controllers/components/security.html

      此答案仅显示如何禁用它们,以防您确定该请求不需要它们。

      原答案

      如果是 ajax 请求,您可以为该特定操作禁用安全组件(相当于在 cake 2.x 中使该操作解锁)

      将此代码放入控制器的beforeFilter

      $actions = [
          'action1',
          'action2'
      ];
      
      if (in_array($this->request->params['action'], $actions)) {
          // for csrf
          $this->eventManager()->off($this->Csrf);
      
          // for security component
          $this->Security->config('unlockedActions', $actions);
      }
      

      禁用 csrf 组件 http://book.cakephp.org/3.0/en/controllers/components/csrf.html#disabling-the-csrf-component-for-specific-actions

      禁用安全组件 http://book.cakephp.org/3.0/en/controllers/components/security.html#disabling-security-component-for-specific-actions

      【讨论】:

      • 为特定操作禁用 CSRF 检查和安全组件可能会导致安全问题。我认为这不是正确的解决方案。
      • @Invincible,你说得对,我编辑了答案以澄清我的意思只是展示如何禁用它,只要确定他在做什么
      • 我接受了@Invincible 的较新答案(曾经是这个),因为它显示了更好的解决方案。
      • @BerryM。肯定的伴侣
      • @dav,如果我正在创建 API 会怎样?
      【解决方案5】:

      我也遇到过同样的事情,但是解决了

      cakephp2.10.2
      
      $this->Security->unlockedActions = array('action1', 'action2');
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-08
        • 2014-11-28
        • 2019-03-01
        • 2016-05-22
        • 2018-10-30
        • 1970-01-01
        相关资源
        最近更新 更多