手动提交symfony表单导致CSRF错误

时间:2016-07-09 14:27:06

标签: forms symfony

我希望能够手动提交包含我创建的数据的symfony表单,但似乎我在提交的数据中缺少CSRF令牌,因此验证失败。

表单很简单 - 只有一个字段(让我们说'名称'作为参数)作为没有约束的文本字段。

$data = [];
if ($someCondition) {
    $data['name'] = 'steve';
}
$form = $this->createForm('FooType', $data);
if (!empty($data)) {
    $form->submit($data);
} else {
    $form->handleRequest($request);
}
if ($form->isSubmitted() && $form->isValid()) {
    // do something
}

如果我设置$data['name']表单提交但我得到The CSRF token is invalid. Please try to resubmit the form.

很明显,我错过了令牌。我知道我可以禁用CSRF保护,但我不想这样做,因为还有一个选项,通常'与表单互动。

如何提交正确的令牌或覆盖此行为?

1 个答案:

答案 0 :(得分:1)

我看到你将此标记为symfony2个问题。考虑到这一点,您可以通过将其注入您的数据提供有效的CSRF令牌,思想,解决方案在<2.6>=2.6版本中有所不同,据我所知。

2.6 版本:

$provider = $this->get('form.csrf_provider');
$token = $provider->generateCsrfToken(''); // INTENTION = empty_string, by default
$data['<<YOUR_FORM_NAME']['_token'] = $token; // be sure to change the form name

版本2.6 +

事情有点不同,因为表单现在使用TokenManagerInterface组件提供的Security

$tokenId = ....;
$token= (string) $this->get('security.csrf.token_manager')->getToken($tokenId);
$tokenValue = $token->getValue();

现在,$tokenId可以是很多东西,如Form的公开测试所述:

$tokenId = $options['csrf_token_id'] ?: 
                ($form->getName() ?: 
                    get_class($form->getConfig()->getType()->getInnerType()));

但是如果你研究一下,默认值为$form->getName(),直到2.8。我认为2.8删除了getName()方法的抽象,因此,2.8以及之后将使用笨重的值:

get_class($form->getConfig()->getType()->getInnerType())

这一切都适用,除非您在表单类型中注入csrf_token_id选项。

<强>更新

好的,所以看来我的错误推定是关于令牌密钥。虽然您确实获得了有效令牌,但未使用该令牌。在我的示例中,我有单独的FormType命名空间AppBundle\Form\SomeFooType,并且使用的实际令牌ID为some_foo

我制作了一个工作示例的pastebin(版本2.8.8,同样在3.1.2按预期工作):http://pastebin.com/ks2jSeh7

希望这有点帮助。