#018 TUTO blog 3 min de lecture

Une authentification MAGIQUE dans Symfony !

Aujourd'hui nous allons voir comment mettre en place une authentification magique dans Symfony ! Notre objectif sera de créer un lien qui permettra à un utilisateur de se connecter sans avoir à saisir son mot de passe.

Version .md Le Markdown brut de l'article, à coller dans Claude Code, Codex ou Cursor.
Aujourd'hui nous allons voir comment mettre en place une authentification magique dans Symfony ! Notre objectif sera de créer un lien qui permettra à un utilisateur de se connecter sans avoir à saisir son mot de passe.
SOMMAIRE · 5 PARTIES
  1. Création d’un projet
  2. Mise en place d’un HomeController et protection
  3. Création d’un formulaire d’enregistrement
  4. Mettons en place un Formulaire de Login “Classique”
  5. Mettons en place (enfin!) le Magic Link :fire:
Voir la vidéo

Création d’un projet

symfony new magicLink --full
cd magickLink
symfony console make:docker:database
symfony console make:user
docker-compose up -d
symfony serve -d
symfony console make:migration
symfony console d:m:m

Mise en place d’un HomeController et protection

 symfony console make:controller Home

On le modifie un tout petit peu.

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HomeController extends AbstractController
{
    /**
     * @Route("/home", name="home")
     */
    public function home(): Response
    {
        return $this->render('home/index.html.twig', [
            'controller_name' => 'HomeController',
        ]);
    }

    /**
     * @Route("/", name="index")
     */
    public function index(): Response
    {
        return $this->redirectToRoute('home');
    }
}

Modification du security.yaml.

    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
         - { path: ^/home, roles: ROLE_USER }

Et test de l’url /home

Création d’un formulaire d’enregistrement

#sans mail ni connexion auto
symfony console make:registration-form

Et stylisons le formulaire (histoire de voir des trucs)

twig:
    default_path: '%kernel.project_dir%/templates'
    form_themes: ['bootstrap_5_layout.html.twig']


when@test:
    twig:
        strict_variables: true

Mettons en place un Formulaire de Login “Classique”

symfony console make:auth

Et modifions le AppAutheticator

<?php

public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
    if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
        return new RedirectResponse($targetPath);
    }
    // For example:
    return new RedirectResponse($this->urlGenerator->generate('home'));
}
protected function getLoginUrl(Request $request): string
{
    return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}

Création du firewall

security:
    # https://symfony.com/doc/current/security/experimental_authenticators.html
    enable_authenticator_manager: true
    # https://symfony.com/doc/current/security.html#c-hashing-passwords
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
        App\Entity\User:
            algorithm: auto

    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider
            custom_authenticator: App\Security\AppAuthenticator
            logout:
                path: app_logout
                # where to redirect after logout
                # target: app_any_route
            login_link:
                check_route: login_check
                signature_properties: ['id']

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
         - { path: ^/, roles: ROLE_USER }

Création de la route

#route.yaml
login_check:
    path: /login_check
<?php

    /**
     * @Route("/magic", name="app_magic")
     */
    public function magic(UserRepository $userRepository, LoginLinkHandlerInterface $loginLinkHandler, MailerInterface $mailer): Response
    {
        $users = $userRepository->findAll();

        foreach ($users as $user) {
            $loginLinkDetails = $loginLinkHandler->createLoginLink($user);
            $email = (new Email())
                ->from('bot@test.com')
                ->to($user->getEmail())
                ->subject('Magic login link')
                ->text('You can use this link to login: ' . $loginLinkDetails->getUrl());

            $mailer->send($email);
        }

        return new Response('Magic!');

    }

Pour que cela fonctionne, nous devons ajouter un Mailer. Utilisons Docker pour cela.

version: '3.7'
services:
    database:
        image: 'mysql:latest'
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: main
        ports:
            # To allow the host machine to access the ports below, modify the lines below.
            # For example, to allow the host to connect to port 3306 on the container, you would change
            # "3306" to "3306:3306". Where the first port is exposed to the host and the second is the container port.
            # See https://docs.docker.com/compose/compose-file/#ports for more information.
            - '3306'
    mailer:
        image: schickling/mailcatcher
        ports: [1025, 1080]

Et demarrons le docker-compose.yaml

docker-compose up -d

Quelques options

        login_link:
            check_route: login_check
            signature_properties: ['id']
            max_uses: 1
            lifetime: 300
Tous les articles

Commentaires (0)

Chargement des commentaires…

Laisser un commentaire