user3599441
user3599441

Reputation:

Redirect to different locations based on the role with FOSUserBundle

I have looked everywhere, and tried everything, but my redirect still doesn't want to work.

I have done option two of this question's answer but the wanted results doesn't appear.

This is my overwritten login function (inside /src/Acme/UserBundle/Controller/SecurityController.php);

class SecurityController extends BaseController
{
    public function loginAction(Request $request)
    {        
        /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
        $session = $request->getSession();

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

I have my AcmeUserBundle.php inside /src/Acme/UserBundle/ containing the following code;

namespace Acme\UserBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class AcmeUserBundle extends Bundle
{
    public function getParent()
    {
        return 'FOSUserBundle';
    }
}

Then I have my main application bundle AppBundle next to Acme inside /src/ with my DefaultController.php inside /Controller/ and my admin controller as DefaultController.php inside /Controller/Admin/

When I log in with a user with role ROLE_USER, it goes to the correct location. But when I log in with role ROLE_ADMIN he goes to the same location as ROLE_USER. It is suppose to go to the admin page.

This is my security.yml file;

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: bcrypt

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: ROLE_ADMIN

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_token_generator: security.csrf.token_manager
            logout:       true
            anonymous:    true

    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, role: ROLE_USER }
        - { path: ^/admin, role: ROLE_ADMIN }

In my project's profiler the user role for a normally registered user state ROLE_USER. I modified a user's role in my database to be ROLE_ADMIN and when I log in with him both roles shows to be assigned to him. Under the role column in my database this is how it looks for a user with ROLE_USER assigned to him :

a:0:{}

and this is how I modified the other user to have ROLE_ADMIN:

a:1:{i:0;s:10:"ROLE_ADMIN";}

Is this right? Can somebody please help me to fix this problem?

NOTE: When I sign in with a ROLE_USER user and I modify the url to go to /admin/ I get a "Expression "has_role('ROLE_ADMIN')" denied access." error. I get that, that's fine because I don't want a normal user to access that area. But when I login with a ROLE_ADMIN user and modify the url to /admin/ it does go to that page, so I can see by that that my ROLES are working fine and the routing as well, but the redirect on login not.

Clearing my cache also didn't do the trick.

Upvotes: 4

Views: 1066

Answers (2)

snoop168
snoop168

Reputation: 404

This is how I did it...

// AppBundle\Security\LoginSuccessHandler.php

namespace AppBundle\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('admin'));
        } 

        return $response;
    }

}

Then add this to your services.yml file:

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

I can't remember if there were other steps.. Pretty sure the services file entry takes care of making sure that class gets called.

Upvotes: 2

malarzm
malarzm

Reputation: 2966

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.

Upvotes: 1

Related Questions