symfony fosuserbundle redirection after login

2019-09-13 16:19发布

问题:

i have a login form what i want to do that if a user have role user tries to login he's redirected to page voiture_new and if an admin eventually has a role admin he's redirected to the admin page PS : i'm using easyadminbundle

here's what i've added to the loginaction of my controller

          $authChecker = $this->container-   >get('security.authorization_checker');
$router = $this->container->get('router');

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

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

and here's my security.yml

    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_email

firewalls:
    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            csrf_token_generator: security.csrf.token_manager
            always_use_default_target_path: false
            default_target_path:  /voiture/new
            check_path: fos_user_security_check

            # if you are using Symfony < 2.8, use the following config instead:
            # csrf_provider: form.csrf_provider

        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: ^/admin/, role: ROLE_ADMIN }
    - { path: ^/marque/, role: ROLE_ADMIN }
    - { path: ^/modele/, role: ROLE_ADMIN }
    - { path: ^/user/, role: ROLE_ADMIN }
    - { path: ^/voiture/, role: ROLE_USER }
    - { path: ^/profile/, role: ROLE_USER }
    - { path: ^/interventions/, role: ROLE_USER }

but always i'mredirected to voiture_new even if the user have a role admin waht i'm missing ?

回答1:

What you need to do is to create Authenticator Class and then tell symfony that use this while trying to authenticate. Inside this class is a method onAuthenticationSuccess you can then use this to perform all the redirect.

For example inside security.yml under firewall which is called main in this case. Tell it that you want to use guard and then mention the service which in this example is called app.form_login_authenticator

main:
    pattern: ^/
    http_basic: ~
    anonymous: ~
    logout:
        path: logout
    guard:
        authenticators:
            - app.form_login_authenticator
        # by default, use the start() function from FormLoginAuthenticator
        entry_point: app.form_login_authenticator

Inside your services.yml make sure this service is listed

app.form_login_authenticator:
        class: AppBundle\Security\FormLoginAuthenticator
        arguments: ["@service_container"]

and then this is the class example

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
    private $container;

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

    public function getCredentials(Request $request)
    {
        if ($request->getPathInfo() != '/login_check') {
            return;
        }

        $username = $request->request->get('_username');
        $request->getSession()->set(Security::LAST_USERNAME, $username);
        $password = $request->request->get('_password');

        return array(
            'username' => $username,
            'password' => $password
        );
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $username = $credentials['username'];    
        $userRepo = $this->container
            ->get('doctrine')
            ->getManager()
            ->getRepository('AppBundle:User');

        return $userRepo->findOneByUsername($username);
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        $plainPassword = $credentials['password'];
        $encoder = $this->container->get('security.password_encoder');
        if (!$encoder->isPasswordValid($user, $plainPassword)) {
            return false;
        }

        return true;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        // AJAX! Maybe return some JSON
        if ($request->isXmlHttpRequest()) {
            return new JsonResponse(
            // you could translate the message
                array('message' => $exception->getMessageKey()),
                403
            );
        }

        // for non-AJAX requests, return the normal redirect
        return parent::onAuthenticationFailure($request, $exception);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        //Perform your redirects here for example


        $response = '';
        if($this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')){
            $response = $this->container->get('router')->generate('admin_dashboard');
        }

        if($this->container->get('security.authorization_checker')->isGranted('ROLE_USER')){
            $response = $this->container->get('router')->generate('user_dashboard');
        }

        return $response;
    }

    protected function getLoginUrl()
    {
        return $this->container->get('router')
            ->generate('login');
    }

}

Hopefully this should put you in right path to implementing what you are looking for,