How to redirect an user to a specific page according to his role in Symfony 2.8 using an EventListener

How to redirect an user to a specific page according to his role in Symfony 2.8 using an EventListener

Although there are simpler methods to redirect an user to a specific page according to his role in your Symfony 2 based application with FOSUserBundle, like handling such thing in some action of a controller of your application:

<?php

/**
 * Redirect users after login based on the granted ROLE
 * @Route("/login/redirect", name="_login_redirect")
 */
public function loginRedirectAction(Request $request)
{
    if($this->isGranted('ROLE_ADMIN'))
    {
        return $this->redirectToRoute('admin_homepage');
    }
    else if($this->isGranted('ROLE_MANAGER'))
    {
        return $this->redirectToRoute('manager_homepage');
    }
    else
    {
        return $this->redirectToRoute('default_homepage');
    }
}

There are developers that love to do the things a little bit more complex, however pretty structured (like implementing the login listener). In this article, we'll share with you the simplest way to implement a login listener that redirect the logged user to a specific user according to his role.

1. Create a login listener

The first that you need to do is to create the LoginListener class that will handle the redirect according to the role of the user, we usually create a directory inside our main bundle namely Listeners and save all the listeners classes inside. So the namespace of the class will be AppBundle\Listeners. The content of the class is the following:

<?php 

// Change the namespace according to the location of this class in your bundle
namespace AppBundle\Listeners;

use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;

class LoginListener
{
    protected $userManager;
    protected $router;
    protected $security;
    protected $dispatcher;
    
    public function __construct(UserManagerInterface $userManager, Router $router, SecurityContext $security, EventDispatcher $dispatcher)
    {
        $this->userManager = $userManager;
        $this->router = $router;
        $this->security = $security;
        $this->dispatcher = $dispatcher;
    }
    
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        $this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
    }
    
    public function onKernelResponse(FilterResponseEvent $event)
    {
        // Important: redirect according to user Role
        if ($this->security->isGranted('ROLE_ADMIN')) {
            $event->setResponse(new RedirectResponse($this->router->generate("admin_homepage")));
        } elseif ($this->security->isGranted('ROLE_MANAGER')) {
            $event->setResponse(new RedirectResponse($this->router->generate("manager_homepage")));
        } else {
            $event->setResponse(new RedirectResponse($this->router->generate("default_homepage")));
        }  
    }
}

The listener will expect 4 arguments that we'll inject later during the registration of the listener. The first argument is the user manager that you have registered for your application, in our case we used FOSUserBundle.

2. Register login listener

After creating the class and modifyng the redirect routes according to the role of the signed user, you need to register this class in the services.yml file of your project with the following snippet (note that the class may change according to the structure of files and namespaces that you follow):

# app/config/services.yml
services:     
    login_listener:
        # path of the previously created class
        class:  AppBundle\Listeners\LoginListener
        arguments:
            userManager: "@fos_user.user_manager"
            router: "@router"
            security: "@security.context"
            dispatcher: "@event_dispatcher"
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

Save changes and clear the cache of your symfony with php app/console cache:clear and access to your application, according to the role of the user.

Happy coding !

Become a more social person