获取CSRF令牌测试,与QUOT; CSRF令牌无效" - 功能AJAX测试 [英] Get the CSRF token in a test, "CSRF token is invalid" - functional ajax test
问题描述
我试图测试在Symfony2中的 AJAX
请求。我正在写一个单元测试,抛出下面的错误在我的应用程序/日志/ test.log中
:
request.CRITICAL:未捕获的PHP异常Twig_Error_Runtime:
上的字符串变量不可能访问的属性(0)
(以下简称CSRF令牌无效,请尝试重新提交表单。)
在... /供应商/枝/枝/ lib中/嫩枝/的template.php:388
我的code是相当直接的。
公共职能testAjaxJsonResponse()
{
$形式['后'] ['标题'] ='测试题;
$形式['后'] ['内容'] ='测试内容;
$形式['后'] ['_令牌'] = $客户 - > getContainer() - >获得(form.csrf_provider') - > generateCsrfToken();
$客户 - >请求('POST','/路径/要/ AJAX /',$形式,阵列(),数组(
HTTP_X请求的,随着'=> XMLHtt prequest',
));
$响应= $客户 - > GETRESPONSE();
$这个 - > assertSame(200,$客户 - > GETRESPONSE() - >的getStatus code());
$这个 - > assertSame(应用/ JSON',$响应 - >包头中>获得(Content-Type的'));
}
这个问题似乎是 CSRF
标记,我可以禁用它的测试,但我真的不希望这样做,我是有工作通过2请求(第一次加载页面的形式,我们抢 _token
和 XMLHtt prequest 使用进行第二次请求code>) - !这显然显得相当愚蠢的和低效的。
解决方案
我们可以生成自己的 CSRF
标记为 AJAX
与要求:
下面的变量 $意向
指的是阵列的关键在你的表单类型选项设置
。
添加意向
在你的表单类型
您将需要添加意向
键。例如:
#AcmeBundle \表\型号\ PostType.php
/ **
*附加字段(如果你想编辑),显示的数值为默认
*
*'csrf_protection'=>真正,
*'csrf_field_name'=> _token',//这必须在你的测试赛
*
* @参数OptionsResolverInterface $解析
* /
公共职能setDefaultOptions(OptionsResolverInterface $解析器)
{
$ resolver->使用setdefaults(阵列(
data_class'=> 尖端\ AcmeBundle \实体\邮报,
//唯一键来帮助生成的秘密令牌
'意向'=> post_type,
));
}
阅读文档
生成CSRF令牌在功能测试
现在我们有一个意向
,我们可以用它在我们的单元测试,以产生一个有效的 CSRF
标记。
/ **
*测试阿贾克斯JSON响应与CSRF令牌
*例使用`POST`实体
*
* PHP的code返回`返回新JsonResponse(真,200);`
* /
公共职能testAjaxJsonResponse()
{
//表单域(确保它们通过验证!)
$形式['后'] ['标题'] ='测试题;
$形式['后'] ['内容'] ='测试内容;
//创建我们的CSRF令牌 - 与$意向=`post_type`
$ csrfToken = $客户 - > getContainer() - >获得(form.csrf_provider') - > generateCsrfToken('post_type');
$形式['后'] ['_令牌'] = $ csrfToken; //将它添加到你的`csrf_field_name`
//模拟Ajax请求
$客户 - >请求('POST','/路径/要/ AJAX /',$形式,阵列(),数组(
HTTP_X请求的,随着'=> XMLHtt prequest',
));
//测试我们得到一个有效的JSON响应
$响应= $客户 - > GETRESPONSE();
$这个 - > assertSame(200,$客户 - > GETRESPONSE() - >的getStatus code());
$这个 - > assertSame(应用/ JSON',$响应 - >包头中>获得(Content-Type的'));
//断言内容
$这 - >的assertEquals(真,$响应 - >的getContent());
$这 - > assertNotEmpty($客户端 - > GETRESPONSE() - >的getContent());
}
I'm trying to test an ajax
request in Symfony2. I'm writing a unit test which is throwing the following error in my 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
My code is fairly straight-forward.
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'));
}
The issue seems to be the CSRF
token, I could disable it for the tests, but I don't really want to do that, I had it working by making 2 requests (the first one loads the page with the form, we grab the _token
and make a second request using with XMLHttpRequest
) - This obviously seems rather silly and inefficient!
Solution
We can generate our own CSRF
token for our ajax
request with:
$client->getContainer()->get('form.csrf_provider')->generateCsrfToken($intention);
Here the variable $intention
refers to an array key set in your Form Type Options
.
Add the intention
In your Form Type
you will need to add the intention
key. e.g:
# 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
Generate the CSRF Token in your Functional test
Now we have that intention
, we can use it in our unit test to generate a valid CSRF
token.
/**
* 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());
}
这篇关于获取CSRF令牌测试,与QUOT; CSRF令牌无效" - 功能AJAX测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!