Last active
November 2, 2021 15:02
-
-
Save nuryagdym/ae946b8e696eb6c1a09c510b4ad66c35 to your computer and use it in GitHub Desktop.
Symfony 4.4 google captcha integration to login form using KarserRecaptcha3Bundle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\EventSubscriber; | |
use App\Form\LoginType; | |
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
use Symfony\Component\Form\FormFactoryInterface; | |
use Symfony\Component\HttpFoundation\RedirectResponse; | |
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; | |
use Symfony\Component\HttpKernel\Event\RequestEvent; | |
use Symfony\Component\HttpKernel\KernelEvents; | |
use Symfony\Component\Security\Core\Security; | |
class LoginSubscriber implements EventSubscriberInterface | |
{ | |
/** | |
* @var FormFactoryInterface | |
*/ | |
private $formFactory; | |
/** | |
* @var FlashBagInterface | |
*/ | |
private $flashBag; | |
public function __construct(FlashBagInterface $flashBag, FormFactoryInterface $formFactory) | |
{ | |
$this->formFactory = $formFactory; | |
$this->flashBag = $flashBag; | |
} | |
/** | |
* @return array | |
*/ | |
public static function getSubscribedEvents() | |
{ | |
/** | |
* 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. | |
*/ | |
return array( | |
KernelEvents::REQUEST => ['onLogin', 9] | |
); | |
} | |
/** | |
* @param RequestEvent $event | |
*/ | |
public function onLogin(RequestEvent $event) | |
{ | |
if ('public_login' !== $event->getRequest()->attributes->get('_route')) { | |
return; | |
} | |
//form generation should be in the same way (createdNamed in this case) as in LoginController | |
$loginForm = $this->formFactory->createNamed(null, LoginType::class); | |
if (!$loginForm->has('captcha')) { | |
return; | |
} | |
$loginForm->handleRequest($event->getRequest()); | |
if (!$loginForm->isSubmitted()) { | |
return; | |
} | |
if (!$loginForm->get('captcha')->isValid()) { | |
$errors = $loginForm->get('captcha')->getErrors(); | |
$message = count($errors) ? $errors[0]->getMessage() : 'Failed to pass robot test'; | |
$this->flashBag->add( | |
'error', | |
$message | |
); | |
$session = $event->getRequest()->getSession(); | |
$session->set(Security::LAST_USERNAME, $loginForm->get('_username')->getData()); | |
//to prevent request to call next event | |
$event->setResponse(new RedirectResponse($event->getRequest()->getRequestUri())); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Form; | |
use Karser\Recaptcha3Bundle\Form\Recaptcha3Type; | |
use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |
use Symfony\Component\Form\Extension\Core\Type\EmailType; | |
use Symfony\Component\Form\Extension\Core\Type\PasswordType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
class LoginType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('_username', EmailType::class, ['attr' => ['placeholder' => 'email'], 'data' => $options['lastUsername']]) | |
->add('_password', PasswordType::class, ['attr' => ['placeholder' => 'password']]) | |
->add('_remember_me', CheckboxType::class, ['required' => false]) | |
; | |
$builder->add('captcha', Recaptcha3Type::class, [ | |
'constraints' => new Recaptcha3(), | |
'action_name' => 'login' | |
]); | |
} | |
public function configureOptions(OptionsResolver $resolver) | |
{ | |
$resolver->setDefaults([ | |
//default csrf parameters defined in Symfony codes. without this configuratio csrf check will fail | |
'csrf_field_name' => '_csrf_token', | |
'csrf_token_id' => 'authenticate', | |
'lastUsername' => null | |
]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment