11

私は Symfony2 を初めて使用しますが、それについてよく読んでいます。まず、symfony 2.1.7 を使用しています。ユーザー設定用の FOSUserBundle。ユーザー名とパスワードを使用して、fos_user-login テンプレートを既にオーバーライドしています。しかし、ログイン用のキャプチャを追加したいです。GregwarCaptchaBundle を見たことがあります。ドキュメントによると、新しいフィールドを FormType に追加する必要があります。私の質問は次のとおりです: symfony または FOSUserBundle のログイン フォーム タイプはどこにありますか? この新しいフィールドを追加したり、上書きしたりできますか? ChangePasswordFormType、ProfileFormType などは存在しますが、LoginFOrmType はありません。それはとても明白かもしれませんが、要点がわかりませんでした.どんな助けも歓迎します.
質問は何らかの解決策
で編集 されています.パットが私を助けてくれた以下のコメントを見てください. で新しいフォーム タイプを作成しまし_username_passwordcaptcha田畑。ユーザー名とパスワードの命名がアンダースコアで始まる場合、'login_check' ルーティングと Symfony 認証には十分です。ただし、Symfony はログイン プロセスにリスナーを使用します。これはUsernamePasswordFormAuthenticationListenerクラスです。Form タイプに captcha フィールドを追加しましたが、ログイン プロセス中は常に無視されます (ページにレンダリングされますが、フィールドは検証されず、単に無視されます)。

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('_username', 'email', array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle')) // TODO: user can login with email by inhibit the user to enter username
        ->add('_password', 'password', array(
        'label' => 'form.current_password',
        'translation_domain' => 'FOSUserBundle',
        'mapped' => false,
        'constraints' => new UserPassword()))
        ->add('captcha', 'captcha');
}

上記のようUsernamePasswordFormAuthenticationListenerに、クラスはフォームの入力値を取得してからリダイレクトします。

public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
    parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
        'username_parameter' => '_username',
        'password_parameter' => '_password',
        'csrf_parameter'     => '_csrf_token',
        'captcha'           => 'captcha',
        'intention'          => 'authenticate',
        'post_only'          => true,
    ), $options), $logger, $dispatcher);

    $this->csrfProvider = $csrfProvider;
}

キャプチャ フィールドが追加されました。

protected function attemptAuthentication(Request $request)
{
    if ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) {
        if (null !== $this->logger) {
            $this->logger->debug(sprintf('Authentication method not supported: %s.', $request->getMethod()));
        }

        return null;
    }

    if (null !== $this->csrfProvider) {
        $csrfToken = $request->get($this->options['csrf_parameter'], null, true);

        if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
            throw new InvalidCsrfTokenException('Invalid CSRF token.');
        }
    }

   // check here the captcha value
    $userCaptcha = $request->get($this->options['captcha'], null, true);
    $dummy = $request->getSession()->get('gcb_captcha');
    $sessionCaptcha = $dummy['phrase'];
   // if captcha is not correct, throw exception
    if ($userCaptcha !== $sessionCaptcha) {
        throw new BadCredentialsException('Captcha is invalid');
    }

    $username = trim($request->get($this->options['username_parameter'], null, true));
    $password = $request->get($this->options['password_parameter'], null, true);

    $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);

    return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}

今、ログイン画面にキャプチャがあります。symfony コードで遊ぶのは良い方法ではありません。自分の関数をオーバーライドして呼び出す方法を見つけたら、投稿します。
別の有用な回答

役に立つかもしれない別の回答を見つけました[リンク] 「ログイン前」イベントなどはありますか?

このソリューションに従って、UsernamePasswordFormAuthenticationListenerクラスをオーバーライドし、セキュリティリスナーsecurity.authentication.listener.form.classパラメーターをオーバーライドするだけです。コードは次のとおりです。

namespace TCAT\StaffBundle\Listener;

use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener as BaseListener; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException;


    class StaffLoginFormListener extends BaseListener
    {
        private $csrfProvider;

        /**
         * {@inheritdoc}
         */
        public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options
= array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
        {
            parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
                'username_parameter' => '_username',
                'password_parameter' => '_password',
                'csrf_parameter'     => '_csrf_token',
                'captcha'           => 'captcha',
                'intention'          => 'authenticate',
                'post_only'          => true,
            ), $options), $logger, $dispatcher);

            $this->csrfProvider = $csrfProvider;
        }

        /**
         * {@inheritdoc}
         */
        protected function attemptAuthentication(Request $request)
        {
            if ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) {
                if (null !== $this->logger) {
                    $this->logger->debug(sprintf('Authentication method not supported: %s.', $request->getMethod()));
                }

                return null;
            }

            if (null !== $this->csrfProvider) {
                $csrfToken = $request->get($this->options['csrf_parameter'], null, true);

                if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
                    throw new InvalidCsrfTokenException('Invalid CSRF token.');
                }
            }

            // throw new BadCredentialsException('Bad credentials');
            $userCaptcha = $request->get($this->options['captcha'], null, true);
            $dummy = $request->getSession()->get('gcb_captcha');
            $sessionCaptcha = $dummy['phrase'];

            if ($userCaptcha !== $sessionCaptcha) {
                throw new BadCredentialsException('Captcha is invalid');
            }

            $username = trim($request->get($this->options['username_parameter'], null, true));
            $password = $request->get($this->options['password_parameter'], null, true);

            $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);

            return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
        }



    }

security.authentication.listener.form.class: TCAT\StaffBundle\Listener\StaffLoginFormListenerapp/config/paramaters.yml に行を追加します ところで、キャプチャ値を確認できます。すべてがうまくいくことを願っています。

4

2 に答える 2

11
Adding Captcha to Symfony2 Login Page

これが素晴らしいアイデアかどうかはわかりません。しかし、それは実行可能です。

Where is the symfony or FOSUserBundle login form type?

ログイン用のフォームタイプはありません。login.html.twigでわかるように、フォームはテンプレートに直接埋め込まれています。

How could you do it?

完全に作成することもできますが、フォームをテンプレートに送信できるようにSecurityControllerをカスタマイズする必要があります。


手順は次のようになります。

1.カスタムを作成しますloginFormType(ビルダーでキャプチャを追加できる場所です)。

2.をオーバーライドしSecurityControllerます (似たようなものを確認するには、こちらを参照してください)。ここでloginActionテンプレートにフォームを渡すことができるように、メソッドをオーバーライドする必要があります。

3.login.html.twigコントローラーから渡されたフォームをレンダリングするようにオーバーライドします


編集:コメントへの回答

ContainerAware を拡張するコントローラーでフォームにアクセスするにはどうすればよいでしょうか?

ベースコントローラーからどのように移行できるかを確認するために、この記事を読むことを強くお勧めします. さて、どうやってこれを行うことができますか?

2 つのオプションがあります。

オプション 1: 簡単な方法

$form = $this->createForm(new LoginFormType(), null);

になります:

$form = $this->get('form.factory')->create(new LoginFormType(), $null);

オプション 2: フォームをサービスとして登録する

1.formType を作成します (通常の手順):loginFormType

2.フォームをサービスとして定義しますacme_user.login.formここに素晴らしい例があります(FOSUserBundle の 1.2 バージョンでは、登録フォームとプロファイル フォームの両方がサービスとして登録されていたため、これがどのように行われたかを示す完璧な例です)。

3.ContainerAware を拡張するコントローラー内でフォームを使用できるようになりました。ここを参照してください。

$form = $this->container->get('acme_user.login.form');
于 2013-02-10T11:13:03.057 に答える
1

への返答: symfony コードで遊ぶのは良い方法ではありません。自分の関数をオーバーライドして呼び出す方法を見つけたら、投稿します。

「UsernamePasswordFormAuthenticationListenerclass」をオーバーライドするには、バンドル内の listner ファイルをコピーし、config.yml ファイルを変更して新しいファイルをロードする必要があります。

parameters:
        security.authentication.listener.form.class: Acme\YourBundle\Security\UsernamePasswordFormAuthenticationListener 

また、コピーしたファイルの名前空間を正しいものに変更する必要があります。

namespace Acme\YourBundle\Security;

最後に、使用部分に「AbstractAuthenticationListener」を追加して、正しくロードします。

use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
于 2015-01-23T10:44:43.837 に答える