How to Redirect to Different Url Based on Roles in Symfony 2

How to redirect to different url based on roles in symfony 2

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);
}
}

Symfony route redirection based on roles

<?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")));
}
}
}

You can implement LoginListener like this that will handle your role based redirection.

How to redirect to different routes depending on role in FOSUserBundle?

Here is the problem. The route at the indexAction is /. Your condition inside the indexAction basically gets interpreted as this: "Does the current route, which is always / because it is called from inside this route, equal to admin_login?" That's why your condition always returns false.

With that logic, the route / always redirects to route login. And the route login always redirects to / because role for login is IS_AUTHENTICATED_ANONYMOUSLY but you are already authenticated (which means your current role is either ROLE_NORMAL or ROLE_ADMIN).

EDIT: Now that I read your comment update, you only need to add the path to access control:

access_control:
- { path: ^/$, role: ROLE_ADMIN }
- { path: ^/product$, role: ROLE_ADMIN }

and do something like the following to default/index:

function indexAction() {
return $this->redirectToRoute('product');
}

EDIT2: If your indexAction doesn't do anything other than redirect to route product, you can remove the controller and add the following to routing.yml:

root:
path: /
defaults:
_controller: FrameworkBundle:Redirect:redirect
route: product
permanent: true

Source

Redirect to different locations based on the role with FOSUserBundle

There is a little known success_handler option in form_login (at least), here you can find a gist with example usage suiting your needs just perfectly.

Redirection after login based on user role

Redirect them both to a controller named indexAction() and Redirect them in the controller based on the role. Something like this:

/**
* @Route("/secure-area", name="homepage")
*/
public function indexAction()
{

if($this->getUser()->hasRole('ROLE_ADMIN'))
return $this->redirect($this->generateUrl('admin_area'));
elseif($this->getUser()->hasRole('ROLE_USER'))
return $this->redirect($this->generateUrl('client_area'));
throw new \Exception(AccessDeniedException::class);
}

EDIT:
You should set the default_target_path to the path above

redirect to a different homepage following user role using FOSUserBundle

First off there is no best practice for this. So I leave that decision of selecting one of these options to you whichever suits you according to your needs.

OPTION 1:

You have to implement an EventListener in this case.

STEP 1)

Register a service

<service id="acme_demo.listener.login" class="Acme\DemoBundle\EventListener\LoginListener" 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>

STEP 2)

Your EventListener itself

class LoginListener
{
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_FACTORY'))
{
$response = new RedirectResponse($this->router->generate('factory_homepage'));
}
elseif ($this->security->isGranted('ROLE_CUSTOMER'))
{
$response = new RedirectResponse($this->router->generate('customer_homepage'));
}
else
{
$response = new RedirectResponse($this->router->generate('default_homepage'));
}

$event->setResponse($response);
}
}

OPTION 2:

You can modify the vendor code at FOSUserBundle\Controller\SecurityController Add the following piece of code to make your loginAction look like this

public function loginAction(Request $request)
{
$securityContext = $this->container->get('security.context');
$router = $this->container->get('router');

if ($securityContext->isGranted('ROLE_FACTORY'))
{
return new RedirectResponse($router->generate('factory_homepage'));
}
elseif ($securityContext->isGranted('ROLE_CUSTOMER'))
{
return new RedirectResponse($router->generate('customer_homepage'));
}
else
{
return new RedirectResponse($router->generate('default_homepage'));
}
}

Symfony2 Redirection for unauthorised page with access_denied_url

First you have to know that access_denied_url is only redirecting non anonymous users. For instance it will redirecte a user with ROLE_MEMBER if it tries to acces a page whose path is only for ROLE_ADMIN.

Here the solution:

You have to create a service (my_entry_point) that will be triggered at the entry-point listener (see security.yml below) and which will redirect the user to the page you want (target_page_for_redirection)

# app/config/security.yml

security:
firewalls:
main:
entry_point: my_entry_point # listener triggered if no token is set while an authentification is needed (access_control)
pattern: ^/

.

#src/Acme/UserBundle/Ressources/Config/services.yml

service
my_entry_point:
class: Acme\UserBundle\Redirection\EntryPointRedirection
arguments: [@router] #needed for URL redirection

.

<?php
namespace Acme\UserBundle\Redirection;

use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface,
Symfony\Component\HttpFoundation\Request,
Symfony\Component\HttpFoundation\RedirectResponse;

class EntryPointRedirection implements AuthenticationEntryPointInterface
{
protected $router;

public function __construct($router)
{
$this->router = $router;
}

public function start(Request $request, AuthenticationException $authException = null)
{
return new RedirectResponse($this->router->generate('target_page_for_redirection'));
}
}


Related Topics



Leave a reply



Submit