It is possible to subscribe to many events in Symfony 2, and login events are no different. You may want to have an authentication listener that increments a user’s failed login attempts so an account can be locked or you may want to set the last login date for a user on a successful login. Symfony will dispatch several events for authentication, including the ‘security.authentication.failure’ event on failed login and the ‘security.interactive_login’ event on successful authentication. You can then create an authentication listener class that subscribes to those events so that code can be executed when they are dispatched.
Let’s start by creating the AuthenticationListener class that will subscribe to these events:
// AuthenticationListener.php namespace path\to\your\class; use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; class AuthenticationListener { /** * onAuthenticationFailure * * @author Joe Sexton <joe@webtipblog.com> * @param AuthenticationFailureEvent $event */ public function onAuthenticationFailure( AuthenticationFailureEvent $event ) { // executes on failed login } /** * onAuthenticationSuccess * * @author Joe Sexton <joe@webtipblog.com> * @param InteractiveLoginEvent $event */ public function onAuthenticationSuccess( InteractiveLoginEvent $event ) { // executes on successful login } }
This class contains two methods, one that will subscribe to an authentication failure event and one that will subscribe to an interactive login event
The next step is to subscribe our class methods to the events. This can be done a few different ways, the first is in your bundle’s Resources/config/services.yml file like this:
# Resources/config/services.yml # authentication failure event listener acme.security.authentication_failure_event_listener: class: path\to\your\class\AuthenticationListener tags: - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure } # authentication success event listener acme.security.interactive_login_listener: class: path\to\your\class\AuthenticationListener tags: - { name: kernel.event_listener, event: security.interactive_login, method: onAuthenticationSuccess }
We have subscribed our two methods to their respective events. Using this method also allows us to inject other services into the class as well.
Another way to subscribe to the events is to add a getSubscribedEvents method to the class so the class looks like this:
// AuthenticationListener.php namespace path\to\your\class; use Symfony\Component\Security\Core\AuthenticationEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; class AuthenticationListener implements EventSubscriberInterface { /** * getSubscribedEvents * * @author Joe Sexton <joe@webtipblog.com> * @return array */ public static function getSubscribedEvents() { return array( AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure', AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onAuthenticationSuccess', ); } /** * onAuthenticationFailure * * @author Joe Sexton <joe@webtipblog.com> * @param AuthenticationFailureEvent $event */ public function onAuthenticationFailure( AuthenticationFailureEvent $event ) { // executes on failed login } /** * onAuthenticationSuccess * * @author Joe Sexton <joe@webtipblog.com> * @param InteractiveLoginEvent $event */ public function onAuthenticationSuccess( InteractiveLoginEvent $event ) { // executes on successful login } }
Learn more about this method on the Symfony Event Dispatcher page
The corresponding services file would be a little different, looking like this:
# Resources/config/services.yml # authentication failure event listener acme.security.authentication_event_listener: class: path\to\your\class\AuthenticationListener tags: - { name: kernel.event_subscriber }
These are two different ways to subscribe to Symfony’s login events! To handle authentication requests or create AJAX powered login forms, check out my article on how to implement an AJAX login form in a Symfony 2 project.
Great post! Was just what I was looking for for the last hour… Do you know a way to grab onto the login event to run some code before it’s processed as a success or a failure?
Want to implement searching the db for an IP address and rejecting it if they’ve had too many unsuccessful attempts.
@alex: one tick you can use is, create custom validator for login form. in that validator you will check IP and if its blocked, simply mark form as invalid + show your error message. this way you completely bypass login mechanism.
Hey,
Thanks for this post.
I started to implement the listener but I had this error when I tried to test the onAuthenticationSuccess event :
Argument 1 passed to Roxino\UserBundle\Listener\AuthenticationListener::onAuthenticationSuccess() must be an instance of Symfony\Component\Security\Http\Event\InteractiveLoginEvent, instance of Symfony\Component\Security\Core\Event\AuthenticationEvent given
so I added :
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
and I change the argument of the onAuthenticationSuccess method to :
public function onAuthenticationSuccess( AuthenticationEvent $event )
Then it finally worked but do you have any idea for explaining this error ?
Great little article, really useful thanks!
Cool! That’s a clever way of lonkiog at it!