首页 > 解决方案 > Cakephp - CSRF 令牌不匹配

问题描述

我在 Cakephp 3.6 中有一个项目,其中 MessageController 中的 3 个动作由 Ajax 调用。但是,我有一个问题,当我向其中一个操作发送请求时,XHR 会返回给我:

{
   "message": "CSRF token mismatch.",
   "url": "\/messages\/changepriority\/8",
   "code": 403,
   "file": "D:\\xampp\\htdocs\\myapp\\vendor\\cakephp\\cakephp\\src\\Http\\Middleware\\CsrfProtectionMiddleware.php",
"line": 195
}

这是我尝试从 Ajax 调用的操作之一:

public function changepriority($id=null) 
{
    $this->autoRender = false;
    $message = $this->Messages->get($id);
    $message->priority = ($message->priority === false) ? true : false;
    if ($this->Messages->save($message)) {
        echo json_encode($message);
    }
}

这是我的ajax:

$(".email-star").click(function(){
        var idmessage = this.id;
        $.ajax({
        headers : {
              'X-CSRF-Token': $('[name="_csrfToken"]').val()
           },
         dataType: "json",
         type: "POST",
         evalScripts: true,
         async:true,
         url: '<?php echo Router::url(array('controller'=>'Messages','action'=>'changepriority'));?>' +'/'+idmessage,
         success: function(data){
            if(data['priority'] === false) {
                $("#imp_" + idmessage).removeClass("fas").removeClass('full-star').addClass( "far" );
            }
            else {
                $("#imp_" + idmessage).removeClass("far").addClass( "fas" ).addClass("full-star");
            }
          }
         });
    });

我已阅读有关 Cross Site Request Forgery 的文档,并尝试先关闭 Csrf 以执行这些操作:

public function beforeFilter(Event $event)
{
     $this->getEventManager()->off($this->Csrf);
}

然后用:

public function beforeFilter(Event $event)
{
     $this->Security->setConfig('unlockedActions', ['index', 'changepriority']);
}

但什么都没有。Xhr 总是返回 CSRF 令牌不匹配。我能做些什么 ?

编辑:

我以这种方式更改操作:

    public function changepriority($id=null) 
{
    $this->autoRender = false;
    $message = $this->Messages->get($id);
    $message->priority = ($message->priority === false) ? true : false;
    if ($this->Messages->save($message)) {
        $content = json_encode($message);
        $this->response->getBody()->write($content);
        $this->response = $this->response->withType('json');
        return $this->response;
    }
}

这样,动作就起作用了。可以这样吗?

标签: phpajaxcakephpcsrfcakephp-3.x

解决方案


首先检查你的$('[name="_csrfToken"]').val()输出。

如果没有得到任何输出,需要检查csrfToken隐藏字段是否存在。只需右键单击您的页面,然后单击View Page Source

如果不存在,则在创建表单时没有遵循正确的方式。基本上,当使用创建表单时Cake\View\Helper\FormHelper,会添加一个包含 CSRF 令牌的隐藏字段。

如果一切正确,请在之后的 ajax 调用中添加以下行header

beforeSend: function (xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('[name="_csrfToken"]').val());
},

附言。cakePHP 不建议禁用 CSRF,大多数开发人员都知道这一点。希望这有帮助。


推荐阅读