Add listener before login

巧了我就是萌 提交于 2021-01-03 08:34:03

问题


I have been creating web application using symfony 3, I have added Recaptcha to my login form using EWZRecaptchaBundle, how I can add a listener before login to verify the validation of Recaptcha.

<form method="post" action="{{ path('mysubmited') }}" id="form-validation" name="form-validation">

 <div class="form-group form-input-icon form-input-icon-right">
 <i class="icmn-spinner11 cat__core__spin"></i>
 <div> {{ form_widget(form.username) }}</div>
 </div>

 <div class="form-group">

 <div>{{ form_widget(form.password) }}</div>
 </div>
 <div class="offset-md-3 col-md-4">
 {% form_theme form 
 'EWZRecaptchaBundle:Form:ewz_recaptcha_widget.html.twig' %}
 {{ form_widget(form.recaptcha) }}
 </div>
 <div class="form-actions">
 <button type="submit" class="btn btn-primary">Connexion</button>
 <label class="ml-3">
 <a href="#" class="swal-btn-lost-password"> Mot de passe oublié ?</a>
 </label>
 </div>
 </form>

Security.yml

    form_login:
        check_path: /mysubmited
        login_path: /login
        username_parameter: "login_form[username]"
        password_parameter: "login_form[password]"
        #recaptcha_parameter: "login_form[recaptcha]"
        csrf_parameter: "login_form[_token]"
        csrf_token_id: a_private_string
        provider: my_provider
        default_target_path: homepage-auth 

SecurityController.php

   /**
     * Login check action.
     *
     * @Route("/mysubmited", name="mysubmited")
     * @throws \RuntimeException
     */
    public function mysubmitedAction(Request $request)
    {

        throw new \RuntimeException('You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.');
    }

回答1:


You can add event subscriber on KernelEvents::REQUEST with priority 9. because class Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener(responsible for registering the events for symfony firewall) has priority 8.

So here is your event subscriber:

class LoginSubscriber implements EventSubscriberInterface
{

    /**
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        if ('LOGIN_ROUTE_NAME' !== $event->getRequest()->attributes->get('_route')) {
            return;
        }
        // get recaptcha from request and validate it.if you want to prevent request to call next event, just set response for event. $event->setResponse($response)
    }

    public static function getSubscribedEvents()
    {
        return [
           KernelEvents::REQUEST => ['onKernelRequest', 9]
        ];
    }
}



回答2:


Here is an example - the magic thin is "Authentication events". Have also a look here -> https://symfony.com/doc/current/components/security/authentication.html

namespace AppBundle\Listener;


use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class LoginListener
{

    private $session;
    private $tokenstorageInterface;
    private $em;
    private $container;

    public function __construct(TokenStorageInterface $tokenStorageInterface)
    {
        $this->tokenstorageInterface = $tokenStorageInterface;
    }


    public function onLogin(InteractiveLoginEvent $event)
    {
        //toDo onLogin
    }

}

Then you have to define a service like this (app/config/services.yml):

# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/book/service_container.html
parameters:
#    parameter_name: value
    account.login_listener.class: AppBundle\Listener\LoginListener


services:
#    service_name:
#        class: AppBundle\Directory\ClassName
#        arguments: ["@another_service_name", "plain_value", "%parameter_name%"]

    # Listeners
    account.login_listener:
        class: "%account.login_listener.class%"
        arguments: ["@security.token_storage"]
        tags:
          - { name: kernel.event_listener, event: security.interactive_login, method: onLogin }



回答3:


I don't see why you are not using the login form in correct way using FormType, you can easily handle recaptcha bundle there.

LoginType.php

namespace AppBundle\Form\Type;

use \EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaTrue;

class LoginType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('username', \Symfony\Component\Form\Extension\Core\Type\TextType::class, array(
                ))
                ->add('password', \Symfony\Component\Form\Extension\Core\Type\PasswordType::class, array(
                ))
                ->add('recaptcha', EWZRecaptchaType::class, array(
                    'attr' => array(
                        'options' => array(
                            'theme' => 'light',
                            'type' => 'image'
                        )
                    ),
                    'mapped' => false,
                    'constraints' => array(
                        new RecaptchaTrue()
                    ),
                    'label' => false
        ));
    }
}

Once if ($form->isValid() && $form->isSubmitted()) { is called it will also check if captcha is correct.

Simple and clean.



来源:https://stackoverflow.com/questions/45173869/add-listener-before-login

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!