`django.utils.http` est un module indispensable pour les développeurs Django, véritablement utile et largement utilisé. Ce module regroupe des fonctions utilitaires essentielles nécessaires pour manipuler le protocole HTTP lui-même ou pour manipuler les URL en toute sécurité. Il se concentre sur la *construction* d'URL et de chaînes de requête, et sur la transmission de données en toute *sécurité* dans un environnement HTTP, et non sur l'*envoi* de requêtes (par exemple, avec la bibliothèque `requests`). Dans ce post, nous allons examiner les fonctionnalités clés de `django.utils.http`. ![django http util deep dive image](/media/whitedec/blog_img/c0fa237054df4f8eb25c18785e3a6426.webp) --- ## 1. Encodage Base64 sûr pour les URL: `urlsafe_base64_encode` / `decode` {#sec-85deb0d2dd81} C'est le moment où ce module brille vraiment. L'encodage Base64 standard inclut des caractères spéciaux comme `+` ou `/`. Ces caractères ont une signification spéciale dans une URL (comme les espaces, les séparateurs de chemin, etc.), ce qui peut poser des problèmes lors de la transmission de valeurs via une URL. `urlsafe_base64_encode` remplace ces caractères par `-` et `_` qui peuvent être utilisés en toute sécurité dans les URL. **Utilisations principales:** * Jetons d'authentification pour l'inscription basée sur l'email * Encodage de l'ID utilisateur (pk) pour les liens de réinitialisation de mot de passe **Exemple:** (Création d'un lien de réinitialisation de mot de passe) ```python from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_str from django.contrib.auth.models import User # 1. Lors de la création du jeton (encodage) user = User.objects.get(username='testuser') # Important: Avant d'encoder, il faut toujours convertir en bytes. uid_bytes = force_bytes(user.pk) uid_token = urlsafe_base64_encode(uid_bytes) print(f"Jeton encodé: {uid_token}") # Exemple: 'Mg' (supposons que user.pk soit 2) # reset_url = f"/password-reset/{uid_token}/..." # 2. Lorsque l'utilisateur clique sur le lien (décodage) try: # Décoder le jeton reçu via l'URL de nouveau en bytes uid_bytes_decoded = urlsafe_base64_decode(uid_token) # Reconvertir en chaîne (ou en entier) user_pk = force_str(uid_bytes_decoded) user = User.objects.get(pk=user_pk) print(f"PK restauré: {user.pk}") except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None ``` > **Remarque:** `force_bytes` et `force_str` se trouvent dans le module `django.utils.encoding` et sont généralement utilisés conjointement avec les fonctions `urlsafe_base64`. --- ## 2. Générateur de chaîne de requête: `urlencode` {#sec-053ddf1192e9} Transforme facilement un objet dictionnaire Python en chaîne de requête pour une requête HTTP GET (par exemple, `?key=value&key2=value2`). **Exemple:** ```python from django.utils.http import urlencode params = { 'page': 3, 'q': 'django rest framework', 'region': 'ja' } # URL encode les clés et valeurs du dictionnaire pour former une chaîne de requête. # Les espaces dans 'django rest framework' seront encodés en toute sécurité avec '+' ou '%20'. query_string = urlencode(params) print(query_string) # Résultat: 'page=3&q=django+rest+framework®ion=ja' ``` --- ## 3. Vérification de redirection sécurisée: `is_safe_url` {#sec-acbb3cb184eb} C'est une fonctionnalité de sécurité très importante. Elle est utilisée pour prévenir les vulnérabilités de type 'Open Redirect'. Il est courant de rediriger les utilisateurs vers la page sur laquelle ils se trouvaient auparavant après la connexion, comme avec `?next=/profile/`. Si un attaquant insère une URL externe telle que `?next=http://malicious-site.com` comme valeur `next`, il pourrait rediriger l'utilisateur vers un site malveillant juste après qu'il se soit connecté. `is_safe_url` vérifie si l'URL donnée appartient au même hôte (domaine) que l'application actuelle, ce qui en fait une URL 'sûre', ou si elle est un chemin relatif. **Exemple:** (Vue de connexion) ```python from django.utils.http import is_safe_url from django.shortcuts import redirect, resolve_url def login_success_redirect(request): # Récupérer la valeur 'next' à partir des paramètres GET. next_url = request.GET.get('next') # 1. La valeur 'next' doit exister et # 2. passer le test is_safe_url pour rediriger vers cette URL. if next_url and is_safe_url( url=next_url, allowed_hosts={request.get_host()}, # Autoriser uniquement l'hôte de la requête actuelle require_https=request.is_secure() # Si la requête actuelle est en HTTPS, la redirection doit l'être aussi. ): return redirect(next_url) # Si ce n'est pas sûr ou si la valeur 'next' est absente, redirige vers la page par défaut. return redirect(resolve_url('main-dashboard')) ``` --- ## 4. Autres fonctions utiles {#sec-e272653990e1} * **`urlquote(value)` / `urlunquote(value)`:** Tandis que `urlencode` construit une chaîne de requête à partir d'un dictionnaire entier, `urlquote` encode les caractères spéciaux (espaces, caractères CJK, etc.) dans une seule chaîne en format `%XX` (encoding par pourcentage). Utile pour créer une partie du chemin URL. * **`parse_http_date(date_str)` / `http_date(timestamp)`:** Utilisés pour analyser ou générer des chaînes de dates au format standard (RFC 1123) utilisées dans les en-têtes HTTP comme `Last-Modified` ou `Expires`. --- ## Résumé {#sec-0a8ca4f4ec83} `django.utils.http` est un excellent exemple de la profondeur avec laquelle Django traite les normes HTTP. En particulier, la transmission sécurisée des jetons via **`urlsafe_base64_encode`** et la sécurité des redirections à l'aide de **`is_safe_url`** sont des fonctionnalités essentielles que tous les développeurs Django doivent connaître. En utilisant ce module, il est possible de rendre le traitement des données HTTP plus sûr et plus robuste.