· 3 min read
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.
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);
}
Mettons en place (enfin!) le Magic Link :fire:
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
Création d’une route qui va envoyer des Logins Link
<?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