PHP: Authentification

Dans ce document, vous serez initié à l’authentification avec PHP et une base de données MySQL.

Pour démarrer, créons une base de données qui stockera les comptes utilisateurs.

/* mysql */
DROP DATABASE IF EXISTS demo_auth;

CREATE DATABASE IF NOT EXISTS demo_auth;

USE demo_auth;

CREATE TABLE tbl_users 
(
    `id` INT PRIMARY KEY AUTO_INCREMENT,
    `username` VARCHAR(50) UNIQUE NOT NULL,
    `password` VARCHAR(128) NOT NULL
);

INSERT INTO tbl_users 
(`username`, `password`)
VALUES 
('maman', '$argon2id$v=19$m=65536,t=4,p=1$ZlVHdGNnejUybzJyYzF3cg$erdxiPjnXY3ZxfP8mxrj7ETtWv7D/ROcPr8lRC/k59k'), 
('papa', '$argon2id$v=19$m=65536,t=4,p=1$UUd0cUp6OVpzTE5QekloaA$Z1igb3NJr2lqr/FK+AJMLjEZMFewTxMA3al6+VU2d/Y'),
('toto', '$argon2id$v=19$m=65536,t=4,p=1$NFhKOVEzTlVKVWh0c0tsUA$1YoRbCsjfhhsQynoxBdGSaKm4jnOyOjoHbh80BKZOR0');

Informations sur les 3 comptes utilisateur :

id username mot de passe mot de passe chiffré avec ARGON_2ID
1 maman azer1234 $argon2id$v=19$m=65536,t=4,p=1$ZlVHdGNnejUybzJyYzF3cg$erdxiPjnXY3ZxfP8mxrj7ETtWv7D/ROcPr8lRC/k59k
2 papa baba0123! $argon2id$v=19$m=65536,t=4,p=1$UUd0cUp6OVpzTE5QekloaA$Z1igb3NJr2lqr/FK+AJMLjEZMFewTxMA3al6+VU2d/Y
3 toto my:PasswOrd $argon2id$v=19$m=65536,t=4,p=1$NFhKOVEzTlVKVWh0c0tsUA$1YoRbCsjfhhsQynoxBdGSaKm4jnOyOjoHbh80BKZOR0

Nous devons créer un répertoire pour ce petit projet dont l’arborescence sera :

/mon_projet/
    - index.php
    - auth.php
    Dao/
        - DbConnect.php
        - AuthRepository.php

/Dao/DbConnect.php : Classe de connexion à la base de données

<?php 
/* /Dao/DbConnect.php */ 
/**
 * Classe de connexion à la base de données  
*/
class DbConnect 
{
    /** @var PDO|null $instance stockage de l'instance PDO unique */
    private static ?PDO $instance = null;

    /**
     * Créer et retourne l'instance PDO 
     * @return PDO l'instance PDO créée
    */
    public static function getInstance(): PDO {
        if(self::$instance === null) {
            self::$instance = new PDO('mysql:host=localhost;port=3306;dbname=demo_auth;charset=utf8', 'root', '');
        }

        return self::$instance;
    }
}

/Dao/AuthRepository.php : Classe d’accès aux données de la table tbl_users

<?php 
/* /Dao/AuthRepository.php */ 

// inclusion de la classe DbConnect qui sera utilisée dans la méthode signIn()
require_once 'Dbconnect.php';

class AuthRepository 
{
    /**
     * Identifie un utilisateur
     * @param string $username le nom d'utilisateur renseigné dans le formulaire
     * @param string $password le mot de passe renseigné dans le formulaire
     * @return array l'utilisateur trouvé (ou un tableau vide si l'utilisateur n'a pas été trouvé)
    */
    public static function signIn(string $username, string $password): array {

        /** @var PDO $db connexion à la base de données */
        $db = Dbconnect::getInstance();

        /** @var array $user le tableau qui contiendra les données de l'utilisateur  */
        $user = [];


        /** @var PDOStatement $stmt initialisation de la requête préparée */
        $stmt = $db->prepare("SELECT * FROM tbl_users WHERE username=:username");

        // exécution de la requêtes préparée
        // execute() retourne true si la requête a été exécutée avec succés, sinon false
        if($stmt->execute([':username' => $username])) {
            // récupération de l'utilisateur
            $user = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if($user === false) { // Si l'utilisateur n'a pas été trouvé
                $user = [];
            }
            else if(!password_verify($password, $user['password'])) { // Si le mot de passe est incorrect
                $user = [];
            }
        }
    
        // fermeture de la requête (pour libérer les ressources)
        $stmt->closeCursor();

        // Retourne l'utilisateur trouvé (ou un tableau vide si l'utilisateur n'a pas été trouvé)
        return $user;
    }
}

/index.php : Formulaire d’identification.

<!-- index.php -->
<style>
    form { width: 800px; margin: auto; }
    label { display:inline-block; width: 200px;}
    div { margin: 10px; }
</style>
<form action="auth.php" method="POST">
    <div>
        <label for="myUsername">Nom d'utilisateur</label>
        <input type="text" name="username" id="myUsername">
    </div>
    <div>
        <label for="myPassword">Mot de passe</label>
        <input type="password" name="password" id="myPassword">
    </div>
    <div>
        <button type="submit">S'identifier</button>
    </div>
</form>

/Auth.php : Traitement du formulaire

<?php 
/* auth.php */

require_once 'Dao/AuthRepository.php';

if(!empty($_POST)) {
    try {
        if(!isset($_POST['username'], $_POST['password'])) {
            throw new Exception('Formulaire incomplet');
        }

        $username = $_POST['username'];
        $password = $_POST['password'];

        $user = AuthRepository::signIn($username, $password);

        if(empty($user)) {
            throw new Exception('Nom d\'utilisateur ou mot de passe incorrect !');
        }

        echo 'Bonjour '.$user['username'].', vous êtes connecté.';
    } 
    catch(Exception $ex) {
        echo $ex->getMessage();
    }
}