如果用户在使用我的 Symfony2 应用程序时在后台退出(由于会话到期或其他原因),我已经实现了一个 JS 层出现在屏幕上,允许用户立即重新登录并继续使用该网站。
问题是,如果用户正在填写表单并被注销,在使用 JS 层重新登录后,他仍在查看具有他已经设法输入的值的相同表单,但他的会话发生了变化。因此表单中的 CSRF 令牌无效。
有没有办法根据当前会话和特定表单生成新的 CSRF 令牌,通过 AJAX 抓取它并在表单中替换?或者也许还有其他解决方案?
我不想禁用 CSRF 保护。
如果用户在使用我的 Symfony2 应用程序时在后台退出(由于会话到期或其他原因),我已经实现了一个 JS 层出现在屏幕上,允许用户立即重新登录并继续使用该网站。
问题是,如果用户正在填写表单并被注销,在使用 JS 层重新登录后,他仍在查看具有他已经设法输入的值的相同表单,但他的会话发生了变化。因此表单中的 CSRF 令牌无效。
有没有办法根据当前会话和特定表单生成新的 CSRF 令牌,通过 AJAX 抓取它并在表单中替换?或者也许还有其他解决方案?
我不想禁用 CSRF 保护。
假设您使用默认的 CSRF Provider,在您的 AJAX 控制器中,您可以获得您的 CSRF Provider 服务并“要求”它重新生成令牌:
/** @var \Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider $csrf */
$csrf = $this->get('form.csrf_provider');
$token = $csrf->generateCsrfToken($intention);
return new Response($token);
/** @var \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface $csrf */
$csrf = $this->get('security.csrf.token_manager');
$token = $csrf->refreshToken($intention);
return new Response($token);
使用它来重新生成 CSRF 令牌(自 Symfony2.4 起):
$csrf = $this->get('security.csrf.token_manager'); //Symfony\Component\Security\Csrf\CsrfTokenManagerInterface
$token = $csrf->refreshToken($intention); // Intention is specified in form type
return new Response($token);
是的,机器人可以获取一个 csrf 令牌并将某些内容发布到表单中,但是由于令牌绑定到会话,所以没关系。CSRF 令牌并非旨在阻止机器人提交表单。
对我来说,更简单的解决方案是在同一个表单上重定向用户,传递已经通过 POST 插入的数据。
这样,令牌将以自动方式再次生成。
此外,您不会丢失数据输入。