在登录表单上禁用CSRF令牌

时间:2013-03-07 11:13:44

标签: symfony login csrf fosuserbundle symfony-2.0

我正在使用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 个答案:

答案 0 :(得分: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();

答案 1 :(得分:18)

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

答案 2 :(得分:1)

如果您使用的是FOSUserBundle,并且只想在登录表单上禁用CSRF保护,则需要执行几个步骤。

步骤1)创建您自己的用户捆绑包&amp;安全控制器文件

为了覆盖内置于FOSU​​serBundle中的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错误。

应该这样做!

答案 3 :(得分:0)

我必须override FOSUserBundle's 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,
    ));