30

I simply want that if admin user or front end user try to access login page even after logged in

/admin/login (admin user) 

OR

/login (front end user)

then they should be redirected back to their related home page like /admin or /

Neeraj
  • 8,625
  • 18
  • 60
  • 89

4 Answers4

65

The easier solution is to add these two lines to your app/config/security.yml:

always_use_default_target_path & default_target_path, e.g.:

firewalls:
    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            csrf_provider: form.csrf_provider
            login_path: /login
            check_path: /login_check
            always_use_default_target_path: false
            default_target_path:            /your/start/path/
electronix384128
  • 6,625
  • 11
  • 45
  • 67
  • 1
    I don't see any role-based decision logic in here. Could you please explain ... why/where this snippet redirects `ROLE_ADMIN` to a different route than `ROLE_USER` ? Your answer has 9 upvotes but obviously doesn't provide the answer to the original question. Am I missing something here? You'd have to additonally set the session variable `_security..target_path` based on the user's role inside a listener for this to work ... – Nicolai Fröhlich Nov 19 '14 at 11:51
  • 1
    The alternative is providing a hidden input field `_target_path` within the login-form itself ... which isn't posssible in case that admins and users use the same login-form. See the [doc](http://symfony.com/doc/current/cookbook/security/form_login.html#control-the-redirect-url-from-inside-the-form) – Nicolai Fröhlich Nov 19 '14 at 11:55
  • 1
    In the default_target_path, you also can use the route name instead the path. – Iago Jun 03 '15 at 05:35
  • "/your/start/path/" is the path you want to redirect to after login is successful. – Josiah Jul 07 '17 at 05:57
  • Thank you! Here is the [doc](https://symfony.com/doc/current/security/form_login.html#changing-the-default-page) – Vasilii Suricov Nov 17 '18 at 15:53
44

Redirecting on login/logout in Symfony2 using LoginHandlers

You should implement the AuthenticationSuccessHandlerInterface to handle the last minute decision when the login success.

Implement the AuthenticationSuccessHandlerInterface:

<?php
// AcmeBundle\Security\LoginSuccessHandler.php

namespace AcmeBundle\Security;

use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;

class LoginSuccessHandler implements AuthenticationSuccessHandlerInterface {

    protected $router;
    protected $authorizationChecker;

    public function __construct(Router $router, AuthorizationChecker $authorizationChecker) {
        $this->router = $router;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token) {

        $response = null;

        if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
            $response = new RedirectResponse($this->router->generate('backend'));
        } else if ($this->authorizationChecker->isGranted('ROLE_USER')) {
            $response = new RedirectResponse($this->router->generate('frontend'));
        }

        return $response;
    }

}

Register your class as a service:

# app/config/services.yml

services:
    authentication.handler.login_success_handler:
        class:  AcmeBundle\Security\LoginSuccessHandler
        arguments:  ['@router', '@security.authorization_checker']

Add a reference to your LoginSuccessHandler class in the firewall

# app/config/security.yml

firewalls:
    main:
        pattern: ^/
            form_login:
                success_handler: authentication.handler.login_success_handler     
Victor Häggqvist
  • 4,484
  • 3
  • 27
  • 35
Nezar Fadle
  • 1,335
  • 13
  • 11
  • It's more cleaner @TurdalievNursultan – Nezar Fadle Dec 27 '16 at 10:53
  • 1
    Best answer. I tried it on Symfony 3.2 and it works perfectly. By the way, if you overwrite FOSUserBundle Security Controller and then code the authorization_checker part right in the code it doesn't recognize the isGranted validation so you can't redirect the user based on the role but if you use this answer everythings works perfectly. Thanks! – Rodolfo Velasco Apr 22 '17 at 18:45
22

You can override FOSUserBundle\Controller\SecurityController and add the following code at the top of loginAction.

use Symfony\Component\HttpFoundation\RedirectResponse;

// ...

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

    if ($authChecker->isGranted('ROLE_ADMIN')) {
        return new RedirectResponse($router->generate('admin_home'), 307);
    } 

    if ($authChecker->isGranted('ROLE_USER')) {
        return new RedirectResponse($router->generate('user_home'), 307);
    }

    // ... 
Saviour Dela
  • 139
  • 1
  • 7
Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • 3
    @venimous I'm talking about **overriding** controller's here ... not modifying 3rd-party code directly. Before downvoting answers ... next time please make sure you actually understand them. Please read the documentation chapter ["How to override any part of a bundle"](http://symfony.com/doc/current/cookbook/bundles/override.html), thanks and happy coding! – Nicolai Fröhlich Apr 22 '14 at 12:38
  • When overriding the controller, do you have to register the 'child' bundle with the AppKernel.php? – Mr B Nov 18 '14 at 17:04
  • 1
    @Sid - yes you have to register the "*child*" bundle with `AppKernel.php` to be able to override the controller in the "*parent*" bundle (FOSUserBundle). – Nicolai Fröhlich Nov 19 '14 at 11:42
  • Why is this the accepted answer? Successful login does not come here at all. If you take a look at original (\FOS\UserBundle\Controller\SecurityController::loginAction), you'll see that this deals with login screen rendering only. Correct solution is to use LoginHandlers, see below. – JohnSmith Sep 07 '16 at 15:19
  • 1
    Before the event-based refactoring (`v2.x`) of FOSUserBundle ... in version `1.x` the internal flow of the bundle was like this. This is a 3 years old answer and it was correct at that time. I can rework it once I have time for this. – Nicolai Fröhlich Sep 07 '16 at 18:30
  • Oh okay. Missed that. Cheers. – JohnSmith Sep 08 '16 at 07:04
  • Not working anymore in symfony4.3, use the answer of Ben Marten. – Keutelvocht Nov 13 '19 at 20:41
3

Just redirect in the controller of the page that you added in default_target_path to the wanted direction, for example, if you put for default_target_path: /index and index is an action defined in HomePageCOntroller, go to HomePageCOntroller, test if the current user is admin or not with:

if (($this->container->get('security.context')->isGranted('ROLE_ADMIN'))) 

and then redircet him to the admin space.

Brendan Green
  • 11,676
  • 5
  • 44
  • 76
chbas
  • 31
  • 2