问题
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