Introduction
Lors de l’authentification via OAuth 2.0, la nécessité de fournir plusieurs paramètres, tels que client_id
, client_secret
, et grant_type
, en plus des informations d’identification de l’utilisateur, peut rendre le processus complexe et propice aux erreurs. Cet article explore comment simplifier cette procédure en utilisant un middleware personnalisé. Ce middleware permet de réduire la charge de saisie pour l’utilisateur en automatisant la gestion des paramètres requis pour l’authentification.
Prérequis
Avant de procéder à la configuration, veuillez vous assurer de satisfaire aux conditions suivantes :
- Disposer d’un environnement Drupal fonctionnel. Pour des instructions détaillées, veuillez consulter Comment installer Drupal dans un conteneur Docker.
- Être familier avec l’authentification OAuth 2.0 et avoir le module Simple OAuth activé sur votre site Drupal. Voir Authentification OAuth 2.0 pour sécuriser JSONavec les modules Consumers et Simple OAuth.
- Maîtriser la création d’un module personnalisé en respectant les bonnes pratiques. Pour plus de détails, reportez-vous à la section Créer un module personnalisé en appliquant les principes SOLID.
Use Case
Nous allons simplifier l’authentification OAuth 2.0 en réduisant le nombre de paramètres nécessaires pour obtenir un token via l’API /oauth/token
. Actuellement, il est nécessaire de fournir plusieurs paramètres, ce qui peut être fastidieux. Pour améliorer l’expérience utilisateur, nous créerons un middleware dans le module personnalisé custom_auth
qui définira des paramètres par défaut de sorte que la requête soit complétée si le client ne fournit pas l’ensemble des informations. Ainsi, l’utilisateur n’aura qu’à entrer son nom d’utilisateur et son mot de passe, tandis que le middleware s’occupera automatiquement d’ajouter les autres paramètres nécessaires à l’authentification.
Le middleware gère également les requêtes de refresh token, où le type de requête (grant_type
) est automatiquement défini comme refresh_token
si un refresh_token
est présent dans la requête. Cela simplifie encore davantage la gestion des tokens en offrant une expérience utilisateur cohérente et sécurisée.
De plus, cette solution permettra aux clients (applications web, mobiles, etc.), selon leurs besoins, de renseigner le client_id
et le grant_type
, qui sont des informations publiques et ne posent pas de problème de sécurité. En revanche, le client_secret
ne doit pas être fourni par des applications web ou mobiles, car il pourrait être exposé aux utilisateurs, compromettant sa confidentialité. Cette approche non seulement simplifie le processus d’authentification, mais renforce également la sécurité en limitant l’exposition des informations sensibles.
Paramètres dans settings.php
Les paramètres nécessaires à l’authentification, comme client_id
, client_secret
, et grant_type
, sont configurés directement dans le fichier web/sites/default/settings.php
de Drupal. Cela permet une gestion centralisée des informations sensibles et des configurations globales, facilitant ainsi l’intégration et la maintenance. Dans la version 6 bêta de Simple OAuth, il n’est plus nécessaire de créer plusieurs consumers en fonction des rôles des utilisateurs. En effet, chaque utilisateur connecté maintient ses droits existants, ce qui simplifie la gestion des consumers et évite la complexité liée à la récupération du consumer approprié selon le rôle, comme c’était le cas dans la version 5 de Simple OAuth. Voici un exemple de configuration :
$config['system.site']['oauth_client_id'] = 'QOf6alZN9a9ZB2bLG0o9qVPeNKCAeMB6UANmcSdXie4'; $config['system.site']['oauth_client_secret'] = 'oauth'; $config['system.site']['oauth_grant_type'] = 'password';
Création du middleware
Nous avons d’abord créé un dossier Middleware dans le répertoire custom_auth/src
pour y placer notre middleware personnalisé. Ce dossier contient le fichier OauthMiddleware.php
, qui implémente le middleware suivant :
<?php namespace Drupal\custom_auth\Middleware; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal; class OauthMiddleware implements HttpKernelInterface { protected $httpKernel; protected $currentUser; protected $entityTypeManager; public function __construct(HttpKernelInterface $httpKernel, AccountInterface $currentUser, EntityTypeManagerInterface $entityTypeManager) { $this->httpKernel = $httpKernel; $this->currentUser = $currentUser; $this->entityTypeManager = $entityTypeManager; } public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response { if (!$this->isOauthTokenRequest($request)) { return $this->httpKernel->handle($request, $type, $catch); } $this->setOauthParameters($request); return $this->httpKernel->handle($request, $type, $catch); } /** * Check if the request is for obtaining an OAuth token. */ private function isOauthTokenRequest(Request $request): bool { return $request->getPathInfo() === '/oauth/token'; } /** * Set OAuth parameters on the request. */ private function setOauthParameters(Request $request): void { $clientId = $this->getOauthClientId(); $clientSecret = $this->getOauthClientSecret(); if ($this->isRefreshTokenRequest($request)) { $this->setRequestParams($request, $clientId, $clientSecret, 'refresh_token'); } else { $grantType = $this->getOauthGrantType(); $this->setRequestParams($request, $clientId, $clientSecret, $grantType); } } /** * Check if the request contains a refresh_token. */ private function isRefreshTokenRequest(Request $request): bool { return $request->request->get('refresh_token') !== null; } /** * Set parameters on the request if necessary. */ private function setRequestParams(Request $request, string $clientId, string $clientSecret, string $grantType): void { $this->setRequestParamIfMissing($request, 'client_id', $clientId); $this->setRequestParamIfMissing($request, 'client_secret', $clientSecret); $this->setRequestParamIfMissing($request, 'grant_type', $grantType); } /** * Set a parameter on the request if it's not already present. */ private function setRequestParamIfMissing(Request $request, string $param, string $value): void { if (!$request->request->get($param)) { $request->request->set($param, $value); } } /** * Retrieve the OAuth client ID from configuration. */ private function getOauthClientId(): string { return \Drupal::config('system.site')->get('oauth_client_id'); } /** * Retrieve the OAuth client secret from configuration. */ private function getOauthClientSecret(): string { return \Drupal::config('system.site')->get('oauth_client_secret'); } /** * Retrieve the OAuth grant type from configuration. */ private function getOauthGrantType(): string { return \Drupal::config('system.site')->get('oauth_grant_type'); } }
Ce middleware intercepte les requêtes adressées à l’API /oauth/token
et automatise l’ajout des paramètres nécessaires à l’authentification. La méthode handle()
vérifie d’abord, via isOauthTokenRequest()
, si la requête concerne l’obtention d’un token OAuth. Si tel est le cas, setOauthParameters()
récupère et complète les paramètres essentiels comme client_id
, client_secret
et grant_type
. Ces informations sont automatiquement extraites des configurations du site via les méthodes getOauthClientId()
, getOauthClientSecret()
et getOauthGrantType()
, qui utilisent \Drupal::config()
pour accéder aux valeurs définies dans le fichier settings.php
. Lorsqu’une requête de rafraîchissement de token est détectée par isRefreshTokenRequest()
, le paramètre grant_type
est défini sur refresh_token
. Les paramètres manquants sont ensuite ajoutés à la requête via setRequestParams()
et setRequestParamIfMissing()
. Une fois complétée, la requête est transmise au gestionnaire principal pour traitement. Cette approche rationalise le processus d’authentification en automatisant la gestion des informations sensibles tout en garantissant sécurité et simplicité.
Configuration du service
Une fois le middleware créé, il doit être enregistré en tant que service pour être utilisé dans l’application Drupal. Ce service est configuré dans le fichier custom_auth.services.yml
pour être injecté dans le pipeline de requêtes HTTP. Voici l’extrait de configuration :
services: custom_auth.oauth_middleware: class: Drupal\custom_auth\Middleware\OauthMiddleware arguments: ['@current_user', '@entity_type.manager'] tags: - { name: http_middleware, priority: 100, after: 'basic_auth' }
Ce fichier enregistre le service custom_auth.oauth_middleware
, utilisant la classe OauthMiddleware
. Ce service est configuré avec deux arguments : @current_user
, représentant le service utilisateur actuel de Drupal, et @entity_type.manager
, le service responsable de la gestion des entités comme les utilisateurs et les contenus. Il est également balisé avec le tag http_middleware
pour intercepter les requêtes HTTP. Sa priorité est définie sur 100, assurant son exécution après le middleware basic_auth
pour ajouter les paramètres OAuth nécessaires.
Test
Pour tester cette configuration, effectuez une requête POST à l’URL /oauth/token
en fournissant uniquement le nom d’utilisateur (username
) et le mot de passe (password
) dans le corps de la requête. Le middleware se chargera automatiquement d’ajouter les paramètres manquants, tels que client_id
, client_secret
, et grant_type
, en utilisant les valeurs définies dans les configurations. Si tout est correctement configuré, l’API OAuth renverra un token d’authentification.
Le test a été réalisé en utilisant Apidog, un outil efficace pour gérer et tester les API.
Conclusion
L’implémentation d’un middleware personnalisé dans Drupal 10 pour la gestion de l’authentification OAuth 2.0 simplifie considérablement le processus de connexion pour les utilisateurs. En réduisant le nombre de paramètres nécessaires dans les requêtes, ce middleware permet aux utilisateurs de se concentrer uniquement sur la saisie de leur nom d’utilisateur et de leur mot de passe, tandis que les autres paramètres essentiels sont automatiquement fournis. Cette solution améliore l’expérience utilisateur en offrant un processus de connexion plus fluide et plus sécurisé, tout en facilitant le développement frontend en évitant la gestion manuelle des paramètres OAuth.
Développeuse fullstack spécialisée en Systèmes d'Information Répartis , diplômée de la section informatique de la Faculté des Sciences et Techniques (FST) de l'UCAD. Je relève avec passion des défis complexes, avec une forte capacité d'adaptation et un engagement pour la collaboration en équipe. Toujours avide d'apprendre, je vise à créer un impact positif et à promouvoir l'excellence organisationnelle dans chaque projet.