17

我正在使用 Symfony2.0 和 FOSUserBundle,并且想在我的登录表单上禁用 csrf 令牌。

我在 config.yml 中的网站上全局禁用了 csrf 保护:

framework:
    csrf_protection:
        enabled:        false

这很好用,我的表单中没有添加 csrf 字段。但是,这不适用于登录表单。仅在此表单上,如果我未在表单中包含以下令牌,则会收到“无效的 CSRF 令牌”错误:

<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />

如何在登录表单上禁用 CSRF 令牌?

4

4 回答 4

29

您可以通过'csrf_protection' => false在其选项数组中设置来禁用表单类中的 CSRF 保护:

class LoginType extends AbstractType
{
    // ...

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class'      => 'Acme\UserBundle\Entity\User',
            'csrf_protection' => false
        );
    }

    // ...

} 

如果您使用 FormBuilder 而不是 AbstractType 类来创建表单,则可以将 options 数组作为第二个参数传递,createFormBuilder()如下所示:

$form = $this->createFormBuilder($users, array('csrf_protection' => false))
        ->add( ... )
        ->getForm();
于 2013-03-07T11:16:47.117 回答
19

如果您只是转到您的 security.yml 文件并从 form_login 指令中删除 csrf_provider,则不需要更新操作类或任何东西。

于 2013-03-11T14:18:43.847 回答
1

如果您正在使用 FOSUserBundle,并且您希望仅在登录表单上禁用 CSRF 保护,则需要遵循几个步骤。

步骤 1) 创建您自己的用户包和安全控制器文件

为了覆盖 FOSUserBundle 中内置的 SecurityController,您必须首先创建自己的用户包。

因此,创建一个名为 app/src/{YourApp}/UserBundle/Controller/SecurityController.php 的文件您应该扩展原始的 SecurityController 类,并复制 loginAction 方法

use FOS\UserBundle\Controller\SecurityController as SecurityControllerOrig;
class SecurityController extends SecurityControllerOrig
{
   public function loginAction(Request $request)
   {
   }
}

在 loginAction 方法中,注释掉或删除这些行:

$csrfToken = $this->container->has('form.csrf_provider')
        ? $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate')
        : null;

然后确保没有任何东西被传递给查看 CSRF 令牌:

return $this->renderLogin(array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => false,
    ));

步骤 2) 在 Symfony 的防火墙 (security.yml) 中禁用 CSRF 检查

确保注释掉 security.yml 中现有的“csrf_provider:”行:

firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                #csrf_provider: form.csrf_provider

步骤 3) 覆盖 FOSUserBundle 的安全控制器 (routing.yml) 的路由

在 routing.yml 中,注释掉这些行:

fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    options:
        expose: true

在注释掉的行下面添加这些行:

#Over-ride the SecurityController of the FOSUserBundle:
fos_user_security_login:
  path: /login
  defaults:  { _controller: YourAppUserBundle:Security:login }
  methods:  [GET]
  options:
    expose: true

fos_user_security_check:
  path: /login_check
  defaults:  { _controller: FOSUserBundle:Security:check }
  methods:  [POST]
  options:
    expose: true

fos_user_security_logout:
  path: /logout
  defaults:  { _controller: FOSUserBundle:Security:logout }
  methods:  [GET]
  options:
    expose: true

注意 1:我只要求它使用自定义 SecurityController 中的 loginAction 方法。其他两种方法转到父类(不确定是否有区别)。

注意2:您需要“expose:true”部分!否则,你会从 fos js 路由包中得到一个 JavaScript 错误。

应该这样做!

于 2013-10-09T19:39:50.513 回答
0

我必须覆盖 FOSUserBundle 的 SecurityController loginAction,其中登录表单被实例化。

我更换了:

$csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate');

return $this->container->get('templating')->renderResponse('FOSUserBundle:Security:login.html.'.$this->container->getParameter('fos_user.template.engine'), array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => $csrfToken,
    ));

和:

return $this->container->get('templating')->renderResponse('FOSUserBundle:Security:login.html.'.$this->container->getParameter('fos_user.template.engine'), array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => false,
    ));
于 2013-03-11T10:04:15.453 回答