17

我正在编写功能测试,我需要发出 ajax 发布请求。“CSRF 令牌无效。请尝试重新提交表单”。如何在我的功能测试中获得令牌?

$crawler = $this->client->request(
  'POST', 
  $url, 
  array(
      'element_add' => array(
          '_token' => '????',
          'name'   => 'bla',
      )

  ), 
  array(), 
  array('HTTP_X-Requested-With' => 'XMLHttpRequest')
);
4

4 回答 4

22

CSRF 令牌生成器是普通的 symfony 2 服务。您可以自己获取服务并生成令牌。例如:

    $csrfToken = $client->getContainer()->get('form.csrf_provider')->generateCsrfToken('registration');
    $crawler = $client->request('POST', '/ajax/register', array(
        'fos_user_registration_form' => array(
            '_token' => $csrfToken,
            'username' => 'samplelogin',
            'email' => 'sample@fake.pl',
            'plainPassword' => array(
                'first' => 'somepass',
                'second' => 'somepass',
            ),
            'name' => 'sampleuser',
            'type' => 'DSWP',
        ),
    ));

generateCsrfToken获取一个重要的参数意图,该意图在测试中和表单中应该相同,否则它会失败。

于 2013-03-06T08:10:56.403 回答
13

经过长时间的搜索(我在 doc 和网络上都没有找到关于如何检索 csrf 令牌的内容)我找到了一种方法:

$extract = $this->crawler->filter('input[name="element_add[_token]"]')
  ->extract(array('value'));
$csrf_token = $extract[0];

在发出请求之前从响应中提取令牌。

于 2012-03-02T10:31:23.833 回答
8

在 symfony 3 中WebTestCase,您需要获取 CSRF 令牌:

$csrfToken = $client->getContainer()->get('security.csrf.token_manager')->getToken($csrfTokenId);

To get the $csrfTokenId, the best way would be to force it in the options of your FormType ():

class TaskType extends AbstractType
{
    // ...

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'csrf_token_id'   => 'task_item',
        ));
    }

    // ...
}

So in this case: $csrfTokenId = "task_item";. Or you you can try to use the default value, that would be the name of your form.

Then use it as a post parameter:

$client->request(
  'POST',
  '/url',
  [
    'formName' => [
      'field' => 'value',
      'field2' => 'value2',
      '_token' => $csrfToken
    ]
  ]
);
于 2016-07-29T14:29:14.197 回答
0

Just in case someone stumble on this, in symfony 5 you get the token this way:

$client->getContainer()->get('security.csrf.token_manager')->getToken('token-id')->getValue();

where 'token-id' is the id that you used in the configureOptions method in your form type, which would look something like this:

public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
           
            "data_class"         => Foo::class,
            "csrf_protection"    => true,
            "csrf_field_name"    => "field_name", //form field name where token will be placed. If left empty, this will default to _token
            "csrf_token_id"      => "token-id", //This is the token id you must use to get the token value in your test
        ]);
    }

Then you just put the token in the request as a normal field.

于 2020-11-10T09:13:55.883 回答