Middleware de Route
Flight prend en charge les middleware de route et de groupe de routes. Un middleware est une fonction qui s'exécute avant (ou après) le rappel de route. C'est un excellent moyen d'ajouter des vérifications d'authentification d'API dans votre code, ou de valider que l'utilisateur a la permission d'accéder à la route.
Middleware de Base
Voici un exemple de base :
// Si vous fournissez uniquement une fonction anonyme, elle sera exécutée avant le rappel de route.
// il n'y a pas de fonctions middleware "après" sauf pour les classes (voir ci-dessous)
Flight::route('/path', function() { echo ' Here I am!'; })->addMiddleware(function() {
echo 'Middleware first!';
});
Flight::start();
// Cela affichera "Middleware first! Here I am!"
Il y a quelques notes très importantes sur les middleware que vous devriez connaître avant de les utiliser :
- Les fonctions middleware sont exécutées dans l'ordre dans lequel elles sont ajoutées à la route. L'exécution est similaire à la façon dont Slim Framework handles this.
- Les "before" sont exécutés dans l'ordre ajouté, et les "after" sont exécutés dans l'ordre inverse.
- Si votre fonction middleware retourne false, toute exécution est arrêtée et une erreur 403 Forbidden est générée. Vous voudrez probablement gérer cela de manière plus élégante avec un
Flight::redirect()
ou quelque chose de similaire. - Si vous avez besoin de paramètres de votre route, ils seront passés sous forme d'un seul tableau à votre fonction middleware. (
function($params) { ... }
oupublic function before($params) {}
). La raison est que vous pouvez structurer vos paramètres en groupes et dans certains de ces groupes, vos paramètres pourraient apparaître dans un ordre différent, ce qui casserait la fonction middleware en se référant au mauvais paramètre. Ainsi, vous pouvez y accéder par nom au lieu de position. - Si vous passez simplement le nom du middleware, il sera automatiquement exécuté par le dependency injection container et le middleware sera exécuté avec les paramètres dont il a besoin. Si vous n'avez pas de conteneur d'injection de dépendances enregistré, il passera l'instance de
flight\Engine
dans le__construct()
.
Classes de Middleware
Les middleware peuvent également être enregistrés en tant que classe. Si vous avez besoin de la fonctionnalité "after", vous devez utiliser une classe.
class MyMiddleware {
public function before($params) {
echo 'Middleware first!'; // Affiche d'abord le middleware
}
public function after($params) {
echo 'Middleware last!'; // Affiche en dernier le middleware
}
}
$MyMiddleware = new MyMiddleware();
Flight::route('/path', function() { echo ' Here I am! '; })->addMiddleware($MyMiddleware); // aussi ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]);
Flight::start();
// Cela affichera "Middleware first! Here I am! Middleware last!"
Gestion des Erreurs de Middleware
Supposons que vous ayez un middleware d'authentification et que vous vouliez rediriger l'utilisateur vers une page de connexion s'il n'est pas authentifié. Vous avez quelques options à votre disposition :
- Vous pouvez retourner false de la fonction middleware et Flight renverra automatiquement une erreur 403 Forbidden, mais sans personnalisation.
- Vous pouvez rediriger l'utilisateur vers une page de connexion en utilisant
Flight::redirect()
. - Vous pouvez créer une erreur personnalisée dans le middleware et arrêter l'exécution de la route.
Exemple de Base
Voici un exemple simple de retour false :
class MyMiddleware {
public function before($params) {
if (isset($_SESSION['user']) === false) { // Vérifie si l'utilisateur est connecté
return false;
}
// comme c'est vrai, tout continue normalement
}
}
Exemple de Redirection
Voici un exemple de redirection de l'utilisateur vers une page de connexion :
class MyMiddleware {
public function before($params) {
if (isset($_SESSION['user']) === false) { // Vérifie si l'utilisateur est connecté
Flight::redirect('/login');
exit;
}
}
}
Exemple d'Erreur Personnalisée
Supposons que vous devez générer une erreur JSON parce que vous construisez une API. Vous pouvez faire cela comme suit :
class MyMiddleware {
public function before($params) {
$authorization = Flight::request()->headers['Authorization']; // Récupère l'en-tête d'autorisation
if(empty($authorization)) {
Flight::jsonHalt(['error' => 'You must be logged in to access this page.'], 403); // Arrête avec une erreur JSON
// ou
Flight::json(['error' => 'You must be logged in to access this page.'], 403);
exit;
// ou
Flight::halt(403, json_encode(['error' => 'You must be logged in to access this page.']));
}
}
}
Regroupement de Middleware
Vous pouvez ajouter un groupe de routes, et ensuite chaque route dans ce groupe aura le même middleware. C'est utile si vous devez regrouper un tas de routes par exemple avec un middleware d'Auth pour vérifier la clé API dans l'en-tête.
// ajouté à la fin de la méthode group
Flight::group('/api', function() {
// Cette route "vide" correspondra à /api
Flight::route('', function() { echo 'api'; }, false, 'api');
// Cela correspondra à /api/users
Flight::route('/users', function() { echo 'users'; }, false, 'users');
// Cela correspondra à /api/users/1234
Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ new ApiAuthMiddleware() ]);
Si vous voulez appliquer un middleware global à toutes vos routes, vous pouvez ajouter un groupe "vide" :
// ajouté à la fin de la méthode group
Flight::group('', function() {
// C'est toujours /users
Flight::route('/users', function() { echo 'users'; }, false, 'users');
// Et c'est toujours /users/1234
Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ ApiAuthMiddleware::class ]); // ou [ new ApiAuthMiddleware() ], c'est la même chose