[Symfony 4] – Gestion des utilisateurs sans FosUserBundle Chapitre 2

@deprecated : nouvelle version => http://blog.dev-web.io/2018/10/30/symfony-4-gestion-utilisateurs-sans-fosuserbundle-v2018-chapitre-1/

Un court chapitre où nous allons juste implémenter la fonction de connexion d’un utilisateur.

Pour cela nous allons avoir besoin de faire encore un peu de configuration, nous allons tout d’abord mettre à jour le firewall principal du fichier secrity.yaml :

security:
    encoders:
        App\Entity\User: bcrypt

    providers:
        database_users:
            entity: { class: App\Entity\User, property: username }

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            # les urls auxquels s'appliquent ce firewall, dans ce cas, ce sont toutes les urls
            pattern: ^/

            # La connexion n'est pas requise sur toutes les pages
            # par exemple la page d'accueil
            anonymous: true

            form_login:
                # Le nom de la route de la page de connexion
                check_path: security_login
                # Le nom de la route où se trouve le formulaire de connexion
                # Si un utilisateur tente d'acceder à une page protégée sans en avoir les droits
                # il sera redirigé sur cette page
                login_path: security_login
                # Securisation des formulaires
                csrf_token_generator: security.csrf.token_manager
                # La page par defaut apres une connexion reussie
                default_target_path: admin

            logout:
                # La route où se trouve le process de deconnexion
                path: security_logout
                # La route sur laquelle doit etre rediriger l'utilisateur apres une deconnexion
                target: index

    access_control:
        # Les regles de securité
        # Là dans ce cas seul les utilisateurs ayant le rôle ROLE_ADMIN
        # peuvent acceder à toutes les pages commençant par /admin
        - { path: '^/admin', roles: ROLE_ADMIN }

On va aussi modifier le fichier framework.yaml pour y ajouter la gestion des sessions et la protection xcrf

framework:
    secret: '%env(APP_SECRET)%'
    #default_locale: en
    csrf_protection: { enabled: true }
    #http_method_override: true

    # uncomment this entire section to enable sessions
    session:
        # With this config, PHP's native session handling is used
        handler_id: ~

    #esi: ~
    #fragments: ~
    php_errors:
        log: true

On va créer notre controller de login et logout, rien de compliqué, dans App/Controller/SecurityController.php :

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController
{
    /**
     * @Route("/login", name="security_login")
     */
    public function login(AuthenticationUtils $helper): Response
    {
        return $this->render('Security/login.html.twig', [
            // dernier username saisi (si il y en a un)
            'last_username' => $helper->getLastUsername(),
            // La derniere erreur de connexion (si il y en a une)
            'error' => $helper->getLastAuthenticationError(),
        ]);
    }

    /**
     * La route pour se deconnecter.
     * 
     * Mais celle ci ne doit jamais être executé car symfony l'interceptera avant.
     *
     *
     * @Route("/logout", name="security_logout")
     */
    public function logout(): void
    {
        throw new \Exception('This should never be reached!');
    }
}

Si ce n’est pas déjà fait, on va créer 1 controller qui contiendra 2 routes : index et admin

La page index sera la landing page de notre site, la page admin sera la partie sécurisée où seul les admins seront autorisés à y accéder :

namespace App\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class IndexController extends Controller
{
    /**
     * @Route("/", name="index")
     */
    public function index()
    {
        return $this->render('index.html.twig');
    }

    /**
     * @Route("/admin", name="admin")
     */
    public function admin()
    {
        return $this->render('Admin/index.html.twig');
    }

}

Et les templates qui vont bien :

index.html.twig

{% extends 'base.html.twig' %}

{% block body %}
    <a href="{{ path('security_login')}}"> Connexion</a>

        
{% endblock %}
Admin/index.html.twig
{% extends 'base.html.twig' %}

{% block body %}
    Bienvenue {{ app.user.username }} !
        
{% endblock %}
On va aussi créer un template pour notre formulaire de connexion, Security/login.html.twig
{% extends 'base.html.twig' %}

{% block body %}
    {% if error %}
        <div class="alert alert-danger">
            {{ error.messageKey }}
        </div>
    {% endif %}

    <div class="row">
        <div class="col-sm-5">
            <div class="well">
                <form action="{{ path('security_login') }}" method="post">
                    <fieldset>
                        <legend><i class="fa fa-lock" aria-hidden="true"></i> Connexion</legend>
                        <div class="form-group">
                            <label for="username">Username</label>
                            <input type="text" id="username" name="_username" value="{{ last_username }}" class="form-control"/>
                        </div>
                        <div class="form-group">
                            <label for="password">Mot de passe</label>
                            <input type="password" id="password" name="_password" class="form-control" />
                        </div>
                        <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"/>
                        <button type="submit" class="btn btn-primary">
                            <i class="fa fa-sign-in" aria-hidden="true"></i> On entre
                        </button>
                    </fieldset>
                </form>
            </div>
        </div>

        
{% endblock %}

A ce point et si on a rien oublié on doit pouvoir se connecter en accédant à la page /login et en saisissant les identifiants qui sont dans votre fichier fixtures.

Dans le prochain chapitre nous verrons comment un utilisateur peut s’inscrire sur le site.
Vous pouvez retrouver les sources complètes ici : https://github.com/gponty/userDemo

29 commentaires

  1. bonjour, merci pour ce tuto
    2 questions :
    quand je clique sur connexion, cela me met que le systeme ne trouve pas le fichier (Security/login.html;twig ) pourtant j’ai bien ? Je passe par un host et virtual host
    host : 127.0.0.1 kcc

    ServerName kcc
    DocumentRoot C:\kcc\public

    AllowOverride All
    Require all granted
    Options -Indexes

    De plus comment activé la bar symfony avec symfony4 ( je parle du app_dev.php)

  2. Bonjour Stephane,
    Désolé pour ma réponse tardive.

    Est-ce que tes fichiers twig se trouvent bien dans c:\kcc\templates\Security\login.html.twig ?

    Pour la toolbar je te recommande d’installer le package debug :
    composer require debug –dev
    (Même si en théorie tu n’auras besoin que de profiler-pack)

    Bonne journée,

  3. Salut,
    super Tuto. j’ai essaye de suivre les étapes. Apres clic j’ai cette erreur: Invalid CSRF token. Peux tu me m’aider a résoudre ce problème?

    Merci d’avance.

    1. Hello et merci,
      Peut-être as-tu oublié cette ligne :

      input type= »hidden » name= »_csrf_token » value= »{{ csrf_token(‘authenticate’) }} »

      ?

      1. c’est un copier coller du tient.
        alors j’ai reussi a le faire partit en mettant une secrure area mais le problème c’est que la redirection ne ce fait plus.

  4. Bonjour,

    Tout d’abord merci pour le tuto, cependant j’ai des problèmes lors de la connexion

    Aucune erreur de compilation du code, tout marche, mais lorsque je m’identifie avec des identifiants injectés dans la base, cela ne fonctionne pas, il me retourne sur une page blanche, et si je force pour aller dans « /admin » il me renvoie dans « /login » et le profiler n’apparaît même plus.

    Que faire ? Merci d’avance

      1. Salut,

        Désolé de la réponse tardive, mais j’ai cherché avec des amis pendant 4 heures, j’ai repris pas à pas ce que tu as fais dans le tutoriel, même copier/coller, ça n’a jamais fonctionner, mais en prenant ton archive github directement, tout à fonctionner directement, donc je ne comprends toujours pas mais j’ai réussi à finaliser mon projet

        Merci d’avance !!

  5. Le tuto est juste énorme !
    Merci.

    Petite précision :
    Lorsque un user déclenche une 403, on catche où l’exception générée ?

      1. J’ai le même problème: Tous mes utilisateurs avec le role ROLE_USER soulèvent cette exception. Faut il les rediriger vers la page d’index dans la clause finally ?

  6. Bonjour,

    Super initiative ce tuto, car les docs Symfony ne sont clairement pas au point !

    Question:

    Est-ce que dans le fichier security.yaml, dans firewalls: main:, il ne faudrait pas ajouter:
    provider: database_users ?

    1. Bonjour, oui bien d’accord avec toi pour la doc symfony !
      Pour le provider: database_users, il y ai déjà (tout en haut de l’article)

  7. Bonjour et merci pour ce tuoto.
    J’ai un message d’erreur lorsque je me rend sur la page login:

    Notice: Undefined property: Symfony\Component\Security\Http\Authentication\AuthenticationUtils::$getLastUsername

    Je ne vois pas mon erreur. Pouvez-vous m’aider ?

  8. Salut ! super tuto !
    SImplement mes messages flash restent en anglais, mon framework est bien décommenté en fr… Mon fichier translation:
    framework:
    default_locale: ‘%locale%’
    translator:
    paths:
    – ‘%kernel.project_dir%/translations’
    fallbacks:
    – ‘%locale%’

    Quand j’ouvre la bare symfony je suis bien en fr… Juste le message flash en cas de mauvais login par exemple reste en francais… Une idée de comment faire ?

    Merci d’avance !

    1. ahahah !! Oui c’est vrai, le problème ne naviguer entre les différentes version de symfony !

      dans le fichier config/packages/translation.yaml
      tu dois avoir :
      framework:
      default_locale: ‘%locale%’

      et dans le fichier config/service.yaml :
      parameters:
      locale: ‘fr’

  9. Bonjour Loskiki,
    Il suffit de modifier le fichier security.yaml
    et de mettre soit username soit email sur cette ligne :
    providers:
    database_users:
    entity: { class: App\Entity\User, property: email }

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.