Authentification des utilisateurs


1Introduction

Cette documentation explique pas-à-pas comment mettre en place un système d'authentification sans mot de passe (passwordless) dans une application Temma.

Le principe est simple : l'utilisateur saisit son adresse email, reçoit un lien magique par email, et en cliquant dessus, il est authentifié. Ce lien n'est utilisable qu'une seule fois et expire au bout d'une heure.

Ce système repose sur deux composants fournis par Temma :

  • Le contrôleur/plugin \Temma\Controllers\Auth : gère le formulaire de connexion, l'envoi des emails et la session utilisateur.
  • L'attribut \Temma\Attributes\Auth : permet de restreindre l'accès aux contrôleurs et actions en fonction de l'authentification, des rôles et des services.

2Prérequis

Pour suivre ce tutoriel, vous avez besoin de :

  • Un projet Temma fonctionnel (voir la page Installation).
  • Une base de données MySQL ou MariaDB configurée dans vos sources de données.
  • Un serveur capable d'envoyer des emails (pour les liens magiques).

3Création de la base de données

Le système d'authentification nécessite deux tables : User (les utilisateurs) et AuthToken (les jetons de connexion envoyés par email).

Exécutez les requêtes SQL suivantes pour créer ces tables :

CREATE TABLE User (
    id               INT UNSIGNED NOT NULL AUTO_INCREMENT,
    date_creation    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    date_last_login  DATETIME,
    date_last_access DATETIME,
    email            TINYTEXT CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
    name             TINYTEXT,
    roles            SET('admin', 'writer', 'reviewer'), -- à personnaliser
    services         SET('articles', 'news', 'images'), -- à personnaliser
    PRIMARY KEY (id),
    UNIQUE INDEX email (email(255))
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

CREATE TABLE AuthToken (
    token         CHAR(64) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
    expiration    DATETIME NOT NULL,
    user_id       INT UNSIGNED NOT NULL,
    PRIMARY KEY (token),
    INDEX expiration (expiration),
    FOREIGN KEY (user_id) REFERENCES User (id) ON DELETE CASCADE
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

Les champs roles et services de la table User sont de type SET : vous devez les personnaliser en fonction des besoins de votre application. Les rôles représentent les fonctions des utilisateurs (administrateur, rédacteur, etc.), et les services représentent les modules auxquels ils ont accès (articles, images, etc.).


4Configuration

Il faut configurer \Temma\Controllers\Auth à la fois comme pré-plugin (pour gérer la session utilisateur sur chaque requête) et comme route (pour rendre accessible le formulaire de connexion).

Ajoutez les éléments suivants dans votre fichier etc/temma.php :

<?php

return [
    'application' => [
        'dataSources' => [
            'db' => 'mysql://user:password@localhost/myDatabase'
        ]
    ],
    'plugins' => [
        '_pre' => [
            '\Temma\Controllers\Auth'
        ]
    ],
    'routes' => [
        'auth' => '\Temma\Controllers\Auth'
    ]
];
  • Lignes 5 à 7 : Configuration de la connexion à la base de données (adaptez à votre environnement).
  • Lignes 10 à 12 : Déclaration du pré-plugin. À chaque requête, il vérifie si l'utilisateur est authentifié et rend ses informations disponibles.
  • Lignes 14 à 16 : Déclaration de la route. Le contrôleur sera accessible via les URLs /auth/login et /auth/logout.

5Personnalisation du template de connexion

Le contrôleur Auth utilise un template Smarty placé dans templates/auth/login.tpl. La version fournie par Temma est minimale ; il vous est recommandé de créer votre propre version.

Voici un exemple de template de formulaire de connexion :

<html>
<head>
    <title>Connexion</title>
</head>
<body>
    <h1>Connexion</h1>
    {if $authError}
        <p style="color: red;">Adresse email inconnue.</p>
    {/if}
    {if $authSent}
        <p style="color: green;">
            Un lien de connexion a été envoyé à votre adresse email.
            Vérifiez votre boîte de réception.
        </p>
    {else}
        <form method="post" action="/auth/login">
            <label for="email">Adresse email :</label>
            <input type="email" id="email" name="email" required />
            <button type="submit">Se connecter</button>
        </form>
    {/if}
</body>
</html>
  • Ligne 7 : Si l'adresse email n'est pas trouvée en base de données, un message d'erreur est affiché.
  • Ligne 10 : Si l'email a bien été envoyé, un message de confirmation est affiché à la place du formulaire.
  • Lignes 16 à 19 : Le formulaire envoie l'adresse email en POST vers /auth/login.

6Test de la connexion

Avant de tester, assurez-vous d'avoir au moins un utilisateur en base de données. Vous pouvez en insérer un manuellement :

INSERT INTO User (email, name) VALUES ('john@example.com', 'John');

Le processus de connexion se déroule ensuite ainsi :

  1. Accédez à /auth/login dans votre navigateur.
  2. Saisissez l'adresse email de l'utilisateur et validez le formulaire.
  3. Un email contenant un lien de connexion est envoyé à cette adresse.
  4. En cliquant sur le lien, l'utilisateur est authentifié et redirigé vers la page d'accueil.

Le lien de connexion est à usage unique et expire après une heure.


7Protéger des pages avec l'attribut Auth

L'attribut Auth permet de restreindre l'accès à des contrôleurs ou des actions en fonction de l'authentification. Il se base sur la variable de template $currentUser définie par le pré-plugin.

Pour protéger un contrôleur entier (toutes ses actions nécessitent d'être authentifié) :

use \Temma\Attributes\Auth as TµAuth;

#[TµAuth]
class Account extends \Temma\Web\Controller {
    public function profile() {
        // accessible uniquement aux utilisateurs authentifiés
    }
    public function settings() {
        // idem
    }
}

Pour protéger uniquement certaines actions :

use \Temma\Attributes\Auth as TµAuth;

class Blog extends \Temma\Web\Controller {
    // accessible à tout le monde
    public function list() { }

    // réservé aux utilisateurs ayant le rôle "writer"
    #[TµAuth('writer')]
    public function create() { }

    // réservé aux utilisateurs ayant accès au service "images"
    #[TµAuth(service: 'images')]
    public function uploadImage() { }

    // réservé aux utilisateurs ayant le rôle "admin" ou "writer"
    #[TµAuth(['admin', 'writer'])]
    public function edit() { }
}

Si un utilisateur non autorisé tente d'accéder à une page protégée, il reçoit une erreur HTTP 401 par défaut. Pour le rediriger vers le formulaire de connexion, ajoutez cette configuration dans etc/temma.php :

<?php

return [
    'x-security' => [
        'authRedirect' => '/auth/login'
    ]
];

Pour enregistrer l'URL demandée afin d'y rediriger l'utilisateur après connexion, utilisez le paramètre storeUrl :

use \Temma\Attributes\Auth as TµAuth;

#[TµAuth(redirect: '/auth/login', storeUrl: true)]
class Account extends \Temma\Web\Controller {
    // ...
}

Ainsi, après connexion, l'utilisateur sera redirigé vers la page qu'il tentait d'atteindre.


8Utiliser les informations utilisateur

Le pré-plugin Auth met à disposition deux variables de template, utilisables dans les templates, les contrôleurs et les plugins :

  • currentUserId : Identifiant de l'utilisateur authentifié (ou null s'il ne l'est pas).
  • currentUser : Données de l'utilisateur (tableau associatif contenant les clés id, email, name, roles, services, etc.).

Voici un exemple d'utilisation dans un template Smarty :

{if $currentUserId}
    <p>Bonjour, {$currentUser.name} !</p>
    {if $currentUser.roles.admin}
        <a href="/admin">Administration</a>
    {/if}
    <a href="/auth/logout">Déconnexion</a>
{else}
    <a href="/auth/login">Connexion</a>
{/if}

Dans un contrôleur, ces variables sont accessibles via $this['currentUserId'] et $this['currentUser'] :

class Account extends \Temma\Web\Controller {
    public function profile() {
        $userId = $this['currentUserId'];
        $user = $this['currentUser'];
        $this['userName'] = $user['name'];
        $this['isAdmin'] = $user['roles']['admin'] ?? false;
    }
}

9Déconnexion

Pour déconnecter un utilisateur, redirigez-le vers l'URL /auth/logout. Il sera automatiquement redirigé vers la page d'accueil après déconnexion.

Exemple de lien de déconnexion dans un template :

<a href="/auth/logout">Déconnexion</a>

Si vous souhaitez rediriger l'utilisateur vers une URL spécifique après connexion (et donc aussi après déconnexion puis reconnexion), configurez le paramètre redirection (voir la section Configuration avancée).


10Configuration avancée

Toutes les options de configuration se placent dans la clé x-security > auth du fichier etc/temma.php.

Personnalisation de l'email

Vous pouvez modifier l'adresse de l'expéditeur, le sujet et le contenu de l'email de connexion :

<?php

return [
    'x-security' => [
        'auth' => [
            'emailSender'  => 'no-reply@monsite.com',
            'emailSubject' => 'Votre lien de connexion',
            'emailText'    => "Bonjour,\n\nVoici votre lien de connexion :\n%s\n\nCe lien est valable 1 heure.\n\nCordialement"
        ]
    ]
];

Le marqueur %s dans le texte est remplacé par l'URL de connexion.

Inscription automatique

Par défaut, seuls les utilisateurs déjà présents en base de données peuvent se connecter. Pour inscrire automatiquement les nouveaux utilisateurs :

<?php

return [
    'x-security' => [
        'auth' => [
            'registration' => true
        ]
    ]
];

Redirection après connexion

Par défaut, l'utilisateur est redirigé vers la page d'accueil après connexion. Vous pouvez modifier cette URL :

<?php

return [
    'x-security' => [
        'auth' => [
            'redirection' => '/mon-compte'
        ]
    ]
];

Notez que si l'attribut Auth a enregistré l'URL demandée (paramètre storeUrl), celle-ci sera utilisée à la place.

Personnalisation des noms de tables et de champs

Si vos tables ou vos champs ont des noms différents des noms par défaut, vous pouvez les redéfinir :

<?php

return [
    'x-security' => [
        'auth' => [
            'userData' => [
                'base'     => 'auth_db',
                'table'    => 'tUser',
                'id'       => 'user_id',
                'email'    => 'user_mail',
                'roles'    => 'user_roles',
                'services' => 'user_services',
            ],
            'tokenData' => [
                'base'       => 'auth_db',
                'table'      => 'tToken',
                'token'      => 'token_hash',
                'expiration' => 'expiration_date',
                'user_id'    => 'fk_user_id',
            ]
        ]
    ]
];

Pour plus de détails sur toutes les options de configuration, consultez la documentation complète du contrôleur/plugin Auth et de l'attribut Auth.