I have one login page on site. I have 4 different tye of users and i want that when they login they go to different page based on their role assigned.
Is there any way?
One way to solve this is to use an event listener on the security.interactive_login
event. In this case I simply attach another listener in that event listener so it will fire on the response. This lets the authentication still happen but still perform a redirect once complete.
<service id="sotb_core.listener.login" class="SOTB\CoreBundle\EventListener\SecurityListener" scope="request">
<tag name="kernel.event_listener" event="security.interactive_login" method="onSecurityInteractiveLogin"/>
<argument type="service" id="router"/>
<argument type="service" id="security.context"/>
<argument type="service" id="event_dispatcher"/>
</service>
And the class...
class SecurityListener
{
protected $router;
protected $security;
protected $dispatcher;
public function __construct(Router $router, SecurityContext $security, EventDispatcher $dispatcher)
{
$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)
{
if ($this->security->isGranted('ROLE_TEAM')) {
$response = new RedirectResponse($this->router->generate('team_homepage'));
} elseif ($this->security->isGranted('ROLE_VENDOR')) {
$response = new RedirectResponse($this->router->generate('vendor_homepage'));
} else {
$response = new RedirectResponse($this->router->generate('homepage'));
}
$event->setResponse($response);
}
}
For Symfony >= 2.6 now would be:
<?php
namespace CommonBundle\Listener;
use Monolog\Logger;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
/** @var Router */
protected $router;
/** @var TokenStorage */
protected $token;
/** @var EventDispatcherInterface */
protected $dispatcher;
/** @var Logger */
protected $logger;
/**
* @param Router $router
* @param TokenStorage $token
* @param EventDispatcherInterface $dispatcher
* @param Logger $logger
*/
public function __construct(Router $router, TokenStorage $token, EventDispatcherInterface $dispatcher, Logger $logger)
{
$this->router = $router;
$this->token = $token;
$this->dispatcher = $dispatcher;
$this->logger = $logger;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
}
public function onKernelResponse(FilterResponseEvent $event)
{
$roles = $this->token->getToken()->getRoles();
$rolesTab = array_map(function($role){
return $role->getRole();
}, $roles);
$this->logger->info(var_export($rolesTab, true));
if (in_array('ROLE_ADMIN', $rolesTab) || in_array('ROLE_SUPER_ADMIN', $rolesTab)) {
$route = $this->router->generate('backend_homepage');
} elseif (in_array('ROLE_CLIENT', $rolesTab)) {
$route = $this->router->generate('frontend_homepage');
} else {
$route = $this->router->generate('portal_homepage');
}
$event->getResponse()->headers->set('Location', $route);
}
}
And services.yml
services:
common.listener.login:
class: CommonBundle\Listener\LoginListener
arguments: [@router, @security.token_storage, @event_dispatcher, @logger]
scope: request
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
Tested in Symfony 3.1
You could also set default path after user login successfully for all users in security.yml file like so:
[config/security.yml]
...
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: /.*
form_login:
login_path: /login
check_path: /login_check
default_target_path: /login/redirect <<<<<<<<<<<<<<<<<<<<<<<<<
logout:
path: /logout
target: /
security: true
anonymous: ~
...
and then in default_target_path
method make simple redirection based on user role. Very straight forward. Some say that the easiest way is always the best way. You decide :)
[SomeBundle/Controller/SomeController.php]
/**
* Redirect users after login based on the granted ROLE
* @Route("/login/redirect", name="_login_redirect")
*/
public function loginRedirectAction(Request $request)
{
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY'))
{
return $this->redirectToRoute('_login');
// throw $this->createAccessDeniedException();
}
if($this->get('security.authorization_checker')->isGranted('ROLE_ADMIN'))
{
return $this->redirectToRoute('_admin_panel');
}
else if($this->get('security.authorization_checker')->isGranted('ROLE_USER'))
{
return $this->redirectToRoute('_user_panel');
}
else
{
return $this->redirectToRoute('_login');
}
}
Works like a charm but keep in mind to always check for most restricted roles downwards in case your ROLE_ADMIN also has privileges of ROLE_USER and so on...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With