Symfony 2 中是否存在某种方式在每次呈现表单时生成 CSRF 令牌?在我的控制器中,我尝试了这样的事情:
$request = $this->get('request');
if ($request->getMethod() != 'POST') {
$csrf = $this->get('form.csrf_provider');
$date= new \DateTime("now");
$this->date = $date->format('Y-m-d H:i:s');
$token = $csrf->generateCsrfToken($this->date);
} elseif($request->getMethod() == "POST") {
$csrf = $this->get('form.csrf_provider');
$token = $csrf->generateCsrfToken($this->date);
}
$form = $this->createFormBuilder()
....
->add('_token','hidden',array(
'data' => $token
))->getForm();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
DO something
}
}
一直在我的请求权令牌哈希中。但是在 bindRequest 更改为从 parameters.ini 中的安全字符串生成的默认哈希之后,isValid 方法肯定会返回 FALSE 响应。存在某种方式,如何调整呢?
编辑 响应解散者的回答,我编辑了我的控制器并创建了我的 CSRF 提供程序,但我仍然收到“CSRF 令牌无效。请尝试重新提交表单”错误。我的 CSRF 提供程序如下所示:
namespace My\Namespace;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
class MyCsrfProvider implements CsrfProviderInterface
{
protected $session;
protected $secret;
protected $datetime;
public function __construct(Session $session, $secret)
{
$this->secret = $secret;
$this->datetime = new \DateTime('now');
$this->session = $session;
}
public function generateCsrfToken($intention)
{
return sha1($this->secret.$intention.$this->datetime->format('YmdHis').$this->getSessionId());
}
public function isCsrfTokenValid($intention, $token)
{
return $token === $this->generateCsrfToken($intention);
}
protected function getSessionId()
{
return $this->session->getId();
}
}
比我添加到 config.yml 服务类:
services:
form.csrf_provider:
class: My\Namespace\MyCsrfProvider
arguments: [ @session, %kernel.secret% ]
控制器我改为:
//any form without _token field
$form = $this->createFormBuilder()
->add('field1')
->add('field2')->getForm()
if ($this->getRequest()->getMethod() == 'POST') {
$request = $this->getRequest();
$form->bindRequest($request);
if ($form->isValid()) {
Do something
return $this->redirect($this->generateUrl('somewhere'));
}
}
在我的哈希中不能在几秒钟内出现问题吗?因为如果我从日期时间格式中删除秒数,它可以工作,但有 1 分钟到期,这不是一个好的解决方案。我想,原因是时间变了。