Symfony tips : Rediriger après le login selon le ROLE de l'utilisateur

Publié le 24 avril 2016
#symfony

Par défaut, l'utilisateur est redirigé vers la dernière page visitée ou la page par défaut spécifiée. Mais comment diriger nos utilisateurs différemment selon leur ROLE ?

Posons le problème :

  • Je veux que l’administrateur soit redirigé vers la page admin
  • Je veux que l’utilisateur lambda soit redirigé vers la page home

Comment faire ?

Par défaut, l’utilisateur est redirigé vers la dernière page qu’il a visitée. On peut modifier cette redirection par défaut en rajoutant default_target_path: /ma-page dans notre fichier security.yml :

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

(J’utilise ici le bundle FOSUserBundle)

Mais nous sommes toujours confrontés à notre problème. Tout le monde sera redirigé vers cette page.

Solution

Pour régler notre problème nous allons créer un service qui aura pour charge de rediriger l’utilisateur selon son rôle, puis nous l’appellerons au bon moment.

Créons tout d’abord notre service :

<?php

namespace AppBundle\Listener;

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

class AfterLoginRedirection implements AuthenticationSuccessHandlerInterface
{
    private $router;

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

    public function onAuthenticationSuccess(Request $request, TokenInterface $token)
    {
        $roles = $token->getRoles();
        $rolesTab = array_map(function ($role) {
            return $role->getRole();
        }, $roles);

        if (in_array('ROLE_ADMIN', $rolesTab, true)) {
            // c'est un aministrateur : on le rediriger vers l'espace admin
            $redirection = new RedirectResponse($this->router->generate('amin'));
        } else {
            // c'est un utilisaeur lambda : on le rediriger vers l'accueil
            $redirection = new RedirectResponse($this->router->generate('homepage'));
        }

        return $redirection;
    }
}

Nous implémentons l’interface AuthenticationSuccessHandlerInterface qui nous fournit la fonction onAuthenticationSuccess(Request $request, TokenInterface $token) qui nous intéresse. Vous pouvez maintenant mettre votre propre logique.

On n'oublie pas d'enregistrer notre service :

services:
    redirect.after.login:
        class: AppBundle\Listener\AfterLoginRedirection
        arguments: ['@router']

Et enfin nous informons le firewall qu’il faut appeler ce service lorsque l’utilisateur a réussi à s’authentifier :

firewalls:
    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            login_path: /
            csrf_token_generator: security.csrf.token_manager
            success_handler: redirect.after.login
        logout: true
        anonymous: true

Et voila !

À propos de l'auteur - gkueny @Occitech

Développeur depuis maintenant 2 ans et demi, j'ai une grande affinité avec le front-end et les tests bien fait. Pas full-stack mais touche à tout, je suis également à l'aise sur du Symfony / php.