0

我正在开发一个 Symfony 2.2 项目,在该项目中,我使用“FOSUserBundle”来保证安全,效果很好。我也在使用“ewzrecaptchabundle”,它也可以正常工作。我的问题是我想在 FOSUserBundle 的登录页面中使用 recaptcha。我按照将验证码添加到 Symfony2 登录页面链接来覆盖防火墙,但仍然在制作新表单并传递 recaptcha 之后它没有检查 recaptcha 值。

我现在编辑了我的代码如下:

我的听众:

 <?php

 /*
  * This file is part of the Symfony package.
  *
  * (c) Fabien Potencier <fabien@symfony.com>
  *
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
 namespace Webmuch\UserBundle\Listener;

 use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener    as BaseListener;
 use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Psr\Log\LoggerInterface;

 /**
   * CanduUserLoginFormListener is the custom implementation of
   * an authentication via a simple form composed of a username and a password.
   *
   * @author Fabien Potencier <fabien@symfony.com>
   */
 class UserLoginFormListener 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'            => 'ewz_recaptcha',
        'intention'          => 'authenticate',
        'post_only'          => true,
    ), $options), $logger, $dispatcher);

    $this->csrfProvider = $csrfProvider;
}

/**
 * {@inheritdoc}
 */
protected function requiresAuthentication(Request $request)
{
    if ($this->options['post_only'] && !$request->isMethod('POST')) {
        return false;
    }

    return parent::requiresAuthentication($request);
}

/**
 * {@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.'); 

        }
    }

    // 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));
    }
}

而我在 parameters.yml 中将其设置为服务,如下所示

 parameters:
    database_driver:   pdo_mysql
    database_host:     localhost
    database_port:     null
    database_name:     Project
    database_user:     root
    database_password: root

    mailer_transport:  smtp
    mailer_host:       smtp.gmail.com
    mailer_auth_mode:  login
    mailer_user:       mymail@gmail.com
    mailer_password:   mymailpassword

    locale:            en
    secret:            ThisTokenIsNotSoSecretChangeIt
    database_path:     null
    security.authentication.listener.form.class:     Webmuch\UserBundle\Listener\UserLoginFormListener

然后在我创建了一个 UserFormType 如下:

      <?php

            /*
           * This file is part of the FOSUserBundle package.
           *
           * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
           *
           * For the full copyright and license information, please view the LICENSE
           * file that was distributed with this source code.
           */

           namespace Webmuch\UserBundle\Form;

               class NewUserLoginFormType extends AbstractType
                {
               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,))
            ->add('recaptcha', 'ewz_recaptcha', array(
                  'attr'          => array(
              'options' => array(
               'theme' => 'red'
                  )
                   ),
                 'label' => "Verification",
                         'property_path' => false,
                 'constraints'   => array(
                    new True()
                         ),
                 'label' => "Enter the words in the box.")) 

                         ->add('recaptcha_challenge_field', 'hidden',  array('property_path' => false))

                         ->add('recaptcha_response_field', 'hidden', array('property_path' => false));
       }

                        public function setDefaultOptions(OptionsResolverInterface $resolver)
                         {
                        $resolver->setDefaults(array(
                              'data_class' => 'Webmuch\UserBundle\Entity\User',
                              'intention'  => 'authenticate',
                            ));
                            }

                       public function getName()
                       {
                      return 'webmuch_user_newloginform';
                        }
                     }

在我的安全控制器中:

                   public function loginAction()
                   {

                    $form = $this->container->get('form.factory')->create(new NewUserLoginFormType());
                    $request = $this->container->get('request');
                    /* @var $request \Symfony\Component\HttpFoundation\Request */
                     $session = $request->getSession();
                     /* @var $session \Symfony\Component\HttpFoundation\Session */

                  // get the error if any (works with forward and redirect -- see below)
                  if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR))               {
                   $error = $request->attributes-    >get(SecurityContext::AUTHENTICATION_ERROR);
                      } elseif (null !== $session && $session->has(SecurityContext::AUTHENTICATION_ERROR)) {
                    $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
                    $session->remove(SecurityContext::AUTHENTICATION_ERROR);
                     } else {
                        $error = '';
                       }

                    if ($error) {
                    // TODO: this is a potential security risk (see http://trac.symfony-                    project.org/ticket/9523)
                   //$error = $error->getMessage();
                    $session = $this->container->get('session');

                    $session->setFlash('error','Invalid Username or Password');

                     return new RedirectResponse($this->container->get('router')- >generate('fos_user_security_login'));
                      }
                      // last username entered by the user
                   $lastUsername = (null === $session) ? '' : $session-  >get(SecurityContext::LAST_USERNAME);

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

                    return $this->renderLogin(array( `enter code here`
                    'last_username' => $lastUsername,
                     'error'         => $error,
                      'csrf_token' => $csrfToken,
                      'form'   => $form->createView(),
                        ));
                       }

最后是 login.html.twig:

                {% extends "::base1.html.twig" %}

               {% block userProfile %}
              {% if error %}
                 <div>{{ error|trans({}, 'FOSUserBundle') }}</div>
               {% endif %}
                <h2 class="gradWellHead">Login here</h2>

             <div class="row-fluid marginBottom10">
             <div class="span6 well">
               <form class="form-horizontal" action="{{ path("fos_user_security_check")                   }}" method="post">
               <input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
                <div class="control-group">
                <label class="control-label" for="username">{{ 'form.username'|trans({},  'FOSUserBundle') }}</label>
                 <div class="controls">
                <input type="text" id="username" name="_username" value="{{ last_username }}" required="required" placeholder="Username"/>
                 </div>
                </div>
               <div class="control-group">
                 <label class="control-label" for="password">{{ 'form.password'|trans({}, 'FOSUserBundle') }}</label>
                <div class="controls">
                <input type="password" id="password" name="_password"  required="required" placeholder="Password"/>
                </div>
               </div>
              <div class="control-group">
                   <label class="control-label" for="recaptcha">Recaptcha</label>
              <div class="controls">
                   {% form_theme form    'EWZRecaptchaBundle:Form:ewz_recaptcha_widget.html.twig' %}
                  {{ form_widget(form.recaptcha, { 'attr': {'options' : {'theme' : 'clean',},} }) }}   
              </div>
             </div>
              <div class="control-group">
                    <div class="controls">
                   <label class="checkbox">
                    <input type="checkbox" id="remember_me" name="_remember_me" value="on" />Remember me?
                </label>

                 <input class="btn" type="submit" id="_submit" name="_submit" value="{{ 'form.submit'|trans({}, 'FOSUserBundle') }}" />
                  <a href="{{ path('fos_user_resetting_request') }}">Forget Password ?</a>
                    {{ facebook_login_button({'autologoutlink': true}) }}
                </div>
               </div>
              </form>
             </div>

         <div class="span6 well">
         <img src="{{asset('img/candu_manifesto_starburst.jpg')}}">
          </div>
           </div>

            {% endblock  %}

如果有任何想法,请帮助我。

提前致谢 !

4

1 回答 1

-2

我通过制作自定义身份验证器解决了这个问题..

于 2014-07-01T07:58:45.493 回答