当我在 CakePHP 3 中嵌入带有 requestAction 的表单时,CSRF 字段丢失

CSRF field is missing when I embed my form with a requestAction in CakePHP 3

我想在网站的多个位置嵌入联系表。

我在 MessagesController.php:

contact() 函数中开发了一个联系表
// MessagesController.php
public function contact()
{
    $this->set('title', 'Contact');
    $message = $this->Messages->newEntity();
    ... // shortened for brevity
    $this->set(compact('message'));
    $this->set('_serialize', ['message']);
}

我在 AppController.phpinitialize() 函数中加载了 CSRF 组件:

// AppController.php
public function initialize()
{
    parent::initialize();
    $this->loadComponent('Csrf');
    ... // shortened for brevity
}

表单使用 contact.ctp 呈现并且工作正常。

我遵循了 CakePHP 的食谱,它建议在一个元素中使用 requestAction(),然后在我想要的地方回显该元素:

// contact_form.ctp
<?php
    echo $this->requestAction(
        ['controller' => 'Messages', 'action' => 'contact']
    );
?>

并且:

// home.ctp
<?= $this->element('contact_form'); ?>

问题是表单呈现良好,但缺少 CSRF 隐藏字段。它应该自动添加到表单中,因为在 AppController.php.

中调用了 CSRF 组件

我想要么使用带有 requestAction() 的元素不是针对这种特殊情况的解决方案,要么我做错了什么。

有什么想法吗?预先感谢您的输入!

请求参数需要手动传递

requestAction() 使用了一个新的 \Cake\Network\Request 实例,并且它没有将 _Token_csrf 参数传递给它,所以这就是事情崩溃的原因。

虽然您可以通过 $extra 参数自己传递它们,例如

$this->requestAction(
    ['controller' => 'Messages', 'action' => 'contact'],
    [
        '_Token' => $this->request->param('_Token'),
        '_csrf' => $this->request->param('_csrf')
    ]
);

改用单元格

我建议改用单元格,它比请求操作更轻量级,而且它在当前请求中运行,因此可以开箱即用地使用 CSRF 组件。

您几乎只需要复制您的控制器操作代码(就您显示的代码而言),并添加一个 loadModel() 调用来加载 Messages table,类似于

src/View/Cell/ContactFormCell.php

namespace App\View\Cell;

use Cake\View\Cell;

class ContactFormCell extends Cell
{
    public function display()
    {
        $this->loadModel('Messages');

        $this->set('title', 'Contact');
        $message = $this->Messages->newEntity();
        // ... shortened for brevity
        $this->set(compact('message'));
        $this->set('_serialize', ['message']);
    }
}

在相应的单元格模板中创建表单

src/Template/Cell/ContactForm/display.ctp

<?php
echo $this->Form->create(
    /* ... */,
    // The URL needs to be set explicitly, as the form is being
    // created in the context of the current request
    ['url' => ['controller' => 'Messages', 'action' => 'contact']]
);
// ...

然后无论你想把表格放在哪里,只要使用<?= $this->cell('ContactForm') ?>

另见