当我在 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.php
的 initialize()
函数中加载了 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') ?>
。
另见
我想在网站的多个位置嵌入联系表。
我在 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.php
的 initialize()
函数中加载了 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
.
我想要么使用带有 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') ?>
。