Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Testing 在测试中获取CSRF令牌_Testing_Symfony_Csrf Protection - Fatal编程技术网

Testing 在测试中获取CSRF令牌

Testing 在测试中获取CSRF令牌,testing,symfony,csrf-protection,Testing,Symfony,Csrf Protection,我正在编写功能测试,需要发出ajax post请求“CSRF令牌无效。请尝试重新提交表单”。如何在功能测试中获取令牌 $crawler = $this->client->request( 'POST', $url, array( 'element_add' => array( '_token' => '????', 'name' => 'bla', ) ), array(

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

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

  ), 
  array(), 
  array('HTTP_X-Requested-With' => 'XMLHttpRequest')
);
经过长时间的搜索(我在doc和网上都没有找到关于如何检索csrf令牌的信息),我找到了一种方法:

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

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

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获得一个重要参数,该参数在测试中应相同,否则将失败。

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

$csrfToken = $client->getContainer()->get('security.csrf.token_manager')->getToken($csrfTokenId);
要获取
$csrfTokenId
,最好的方法是使用
FormType
():

因此在本例中:
$csrfTokenId=“task\u item”。或者您可以尝试使用默认值,即表单的名称

然后将其用作post参数:

$client->request(
  'POST',
  '/url',
  [
    'formName' => [
      'field' => 'value',
      'field2' => 'value2',
      '_token' => $csrfToken
    ]
  ]
);

为了防止有人无意中发现,在symfony 5中,您可以通过以下方式获得令牌:

$client->getContainer()->get('security.csrf.token_manager')->getToken('token-id')->getValue();
其中“token id”是您在表单类型的configureOptions方法中使用的id,如下所示:

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
        ]);
    }

然后,您只需将令牌作为普通字段放入请求中。

如何知道表单中使用的$intention参数是什么?您可以使用任何想要的$intention,只需确保它与您在Symfony 3中检查令牌时使用的相同。
->get('form.csrf_provider')返回的服务不推荐使用。
。改用
->get('security.csrf.token\u manager')
。方法是
->get('security.csrf.token\u manager')->getToken($intention)
。如果您在测试中对用户进行任何身份验证,请确保首先生成令牌,以避免模拟会话存储在会话启动后试图设置会话ID。如果您不确定其意图,则可能是
'form'
。但是如果它没有设置在任何明显的地方(Symfony magic正在设置它),那么您可以临时编辑
vendor/Symfony/Symfony/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php
以在
getToken()
方法中使用
$tokenId
参数抛出异常,除非您的页面是多格式的或其他复杂的,否则异常应该告诉您
$intention
参数。这是可行的,但这取决于测试的目的:如果是行为测试,复制浏览器行为,那么这肯定是一条路要走(这是一种浏览器所做的);但如果是集成测试,检查控制器是否与CSRF框架正确集成,如果可以,最好通过令牌管理器。这是symfony3的当代答案,应该更积极地进行投票。它结合了已接受答案的信息、注释,并以文档化的方式设置
$tokenId
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
        ]);
    }