在测试中获取 CSRF 令牌,“CSRF 令牌无效” - 功能性 ajax 测试
Posted
技术标签:
【中文标题】在测试中获取 CSRF 令牌,“CSRF 令牌无效” - 功能性 ajax 测试【英文标题】:Get the CSRF token in a test, "CSRF token is invalid" - functional ajax test 【发布时间】:2014-08-20 06:55:22 【问题描述】:我正在尝试在 Symfony2 中测试 ajax
请求。我正在编写一个单元测试,它在我的app/logs/test.log
中引发以下错误:
request.CRITICAL: Uncaught php Exception Twig_Error_Runtime:
"Impossible to access an attribute ("0") on a string variable
("The CSRF token is invalid. Please try to resubmit the form.")
in .../vendor/twig/twig/lib/Twig/Template.php:388
我的代码相当简单。
public function testAjaxJsonResponse()
$form['post']['title'] = 'test title';
$form['post']['content'] = 'test content';
$form['post']['_token'] = $client->getContainer()->get('form.csrf_provider')->generateCsrfToken();
$client->request('POST', '/path/to/ajax/', $form, array(), array(
'HTTP_X-Requested-With' => 'XMLHttpRequest',
));
$response = $client->getResponse();
$this->assertSame(200, $client->getResponse()->getStatusCode());
$this->assertSame('application/json', $response->headers->get('Content-Type'));
问题似乎是CSRF
令牌,我可以为测试禁用它,但我真的不想这样做,我通过发出 2 个请求让它工作(第一个使用表单,我们抓取_token
并使用XMLHttpRequest
发出第二个请求) - 这显然看起来相当愚蠢和低效!
【问题讨论】:
【参考方案1】:解决方案
我们可以为我们的ajax
请求生成我们自己的CSRF
令牌:
$client->getContainer()->get('form.csrf_provider')->generateCsrfToken($intention);
这里的变量$intention
指的是Form Type Options
中设置的数组键。
添加intention
在您的Form Type
中,您需要添加intention
键。例如:
# AcmeBundle\Form\Type\PostType.php
/**
* Additional fields (if you want to edit them), the values shown are the default
*
* 'csrf_protection' => true,
* 'csrf_field_name' => '_token', // This must match in your test
*
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
$resolver->setDefaults(array(
'data_class' => 'Acme\AcmeBundle\Entity\Post',
// a unique key to help generate the secret token
'intention' => 'post_type',
));
Read the documentation
在您的功能测试中生成 CSRF 令牌
现在我们有了intention
,我们可以在单元测试中使用它来生成有效的CSRF
令牌。
/**
* Test Ajax JSON Response with CSRF Token
* Example uses a `post` entity
*
* The PHP code returns `return new JsonResponse(true, 200);`
*/
public function testAjaxJsonResponse()
// Form fields (make sure they pass validation!)
$form['post']['title'] = 'test title';
$form['post']['content'] = 'test content';
// Create our CSRF token - with $intention = `post_type`
$csrfToken = $client->getContainer()->get('form.csrf_provider')->generateCsrfToken('post_type');
$form['post']['_token'] = $csrfToken; // Add it to your `csrf_field_name`
// Simulate the ajax request
$client->request('POST', '/path/to/ajax/', $form, array(), array(
'HTTP_X-Requested-With' => 'XMLHttpRequest',
));
// Test we get a valid JSON response
$response = $client->getResponse();
$this->assertSame(200, $client->getResponse()->getStatusCode());
$this->assertSame('application/json', $response->headers->get('Content-Type'));
// Assert the content
$this->assertEquals('true', $response->getContent());
$this->assertNotEmpty($client->getResponse()->getContent());
【讨论】:
请注意,从 Symfony 2.3 开始,服务名称是security.csrf.token_manager
而不是 form.csrf_provider
。以上是关于在测试中获取 CSRF 令牌,“CSRF 令牌无效” - 功能性 ajax 测试的主要内容,如果未能解决你的问题,请参考以下文章
CSRF 令牌无效。请尝试重新提交表单。 Symfony 4
Symfony3 中的错误“CSRF 令牌无效。请尝试重新提交表单”