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.

5 comments on “Create an Authentication Listener in Symfony 2

  1. Alex says:

    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.

  2. gondo says:

    @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.

  3. Adrien says:

    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 ?

  4. Luke Rotherfield says:

    Great little article, really useful thanks!

    1. Lilly says:

      Cool! That’s a clever way of lonkiog at it!

Comments are closed.