Symfony2.0とFOSUserBundleを使用しており、ログインフォームでcsrfトークンを無効にしたいと考えています。
Config.ymlのWebサイトでcsrf保護をグローバルに無効にしました:
framework:
csrf_protection:
enabled: false
これはうまく機能しており、フォームにcsrfフィールドが追加されていません。ただし、これはログインフォームには適用されません。このフォームでのみ、フォームにトークンを含めないと、「無効なCSRFトークン」エラーが発生します。
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
ログインフォームでCSRFトークンを無効にするにはどうすればよいですか?
Security.ymlファイルに移動し、form_loginディレクティブからcsrf_providerを削除するだけの場合は、アクションクラスなどを更新する必要はありません。
オプション配列に_'csrf_protection' => false
_を設定すると、フォームクラスのCSRF保護を無効にできます。
_class LoginType extends AbstractType
{
// ...
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Acme\UserBundle\Entity\User',
'csrf_protection' => false
);
}
// ...
}
_
AbstractBuilderクラスの代わりにFormBuilderを使用してフォームを作成する場合は、次のように、createFormBuilder()
の2番目のパラメータとしてオプション配列を渡すことができます。
_$form = $this->createFormBuilder($users, array('csrf_protection' => false))
->add( ... )
->getForm();
_
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つのメソッドは、親クラスに行きます(違いがあるかどうかはわかりません)。
注2:「expose:true」の部分が必要です!そうしないと、fos jsルーティングバンドルからJavaScriptエラーが発生します。
それでうまくいくはずです!
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,
));