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)
YourEventListener
itselfclass 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
Accessing a Variable Defined in a Parent Function
How to Add Commas to Numbers in PHP
Set Character Set Using MySQLi
PHP Array Printing Using a Loop
Safe Alternatives to PHP Globals (Good Coding Practices)
Navigate Back with PHP Form Submission
How to Change the Array Key to Start from 1 Instead of 0
If You Create a Variable Inside a If Statement Is It Available Outside the If Statement
How to Capture Search Term from Google Search
Accented Characters in MySQL Table
How to Convert a String to an Array in PHP
JSON: PHP to JavaScript Safe or Not
PHP Put a Space in Front of Capitals in a String (Regex)
How to Send Money to Paypal Using PHP
How to Disable Mod_Security in .Htaccess File
Laravel 5.2: the Process Class Relies on Proc_Open, Which Is Not Available on Your PHP Installation