在测试中获取CSRF令牌

bux*_*bux 15 testing symfony csrf-protection

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

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

  ), 
  array(), 
  array('HTTP_X-Requested-With' => 'XMLHttpRequest')
);
Run Code Online (Sandbox Code Playgroud)

小智 20

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',
        ),
    ));
Run Code Online (Sandbox Code Playgroud)

该generateCsrfToken得到一个重要参数的意图应该是在测试和形式,否则失败一样.

  • 在Symfony 3中,不推荐使用` - > get('form.csrf_provider')`返回的服务.请改用` - > get('security.csrf.token_manager'). (6认同)
  • 方法是` - > get('security.csrf.token_manager') - > getToken($ intention)`.如果在测试中对用户进行任何身份验证,请确保首先生成令牌,以避免模拟会话存储在会话启动后尝试设置会话ID. (2认同)
  • 如果你不确定意图,那么它可能就是"形式".但如果它没有明显设置(Symfony魔术设置它),那么你可以暂时编辑`vendor/symfony/symfony/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php`以使用`$ tokenId抛出异常参数,在`getToken()`方法中,除非你的页面是多重形式或其他复杂的,否则异常应该告诉你`$ intention`参数. (2认同)

bux*_*bux 12

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

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

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


mag*_*tik 6

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

$csrfToken = $client->getContainer()->get('security.csrf.token_manager')->getToken($csrfTokenId);
Run Code Online (Sandbox Code Playgroud)

要获得$csrfTokenId,最好的方法是强制它在你的FormType()的选项中:

class TaskType extends AbstractType
{
    // ...

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下:$csrfTokenId = "task_item";.或者您可以尝试使用默认值,即表单的名称.

然后将其用作post参数:

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