Rafraîchissement automatique des jetons JWT dans Dio : Intercepteur et QueryInterceptor
Les serveurs vérifient l'autorisation via l'en-tête Authorization au format <schéma-d'authentification> <paramètres-d'authentification>. Un middleware traite cet en-tête pour tous les points d'accès protégés. Si des données sont manquantes ou invalides, il renvoie 401 Non autorisé ou 403 Interdit.
Principaux schémas :
- Basic : Identifiant:mot de passe encodé en Base64 (
Authorization: Basic bG9naW46cGFzc3dvcmQ=). Faible sécurité en raison du décodage facile. - Bearer : Jeton JWT (
Authorization: Bearer <Token>). Prend en charge l'expiration, nécessite un rafraîchissement.
Le JWT se compose de l'en-tête (algorithme), de la charge utile (données utilisateur, exp) et de la signature (secret du serveur). Format : {En-tête}.{Charge utile}.{Signature} en Base64.
Structure du JWT et rafraîchissement
La charge utile contient exp (date d'expiration). En cas de 401, les clients demandent un rafraîchissement via un point d'accès protégé sans middleware.
Systèmes à double jeton :
- Jeton d'accès : Durée de vie courte (minutes), pour les requêtes API.
- Jeton de rafraîchissement : Durée de vie longue, pour générer de nouveaux jetons d'accès.
Stratégies pour gérer les jetons expirés
Déconnexion (approche la plus simple)
En cas de 401 — déconnexion. L'implémentation est triviale mais peu pratique pour les utilisateurs.
Avantages :
- Code minimal.
Inconvénients :
- Reconnexions fréquentes.
- Incompatible avec le double jeton.
Rafraîchissement en cas d'erreur (Intercepteur)
Implémenté via Interceptor dans Dio. Ajoute le jeton dans onRequest, gère le 401 dans onError.
class TokenInterceptor extends Interceptor {
final TokenStorage _storage;
TokenInterceptor(this._storage);
@override
Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
final token = await _storage.getToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
}
Configuration :
final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));
Dans onError pour 401 :
- Vérifier le drapeau
_isRefreshing. - Si non — initier le rafraîchissement via un Dio séparé.
- Les requêtes en attente attendent via
Completer<void> _refreshCompleter.
Future<String?> _updateToken() async {
final oldToken = await _storage.getToken();
try {
final dio = Dio();
final response = await dio.get('/auth/refresh/', headers: {'Authorization': 'Bearer $oldToken'});
final newToken = (response.data as Map<String, dynamic>)['token'];
await _storage.setNewToken(newToken);
return newToken;
} catch (e) {
await _storage.clearToken();
return null;
}
}
La logique complète de onError synchronise les requêtes parallèles, réessaie avec le nouveau jeton.
Avantages :
- Fonctionne avec le double jeton.
- Aucune bibliothèque externe.
Inconvénients :
- Charge en vague sur le serveur avec réessais massifs.
- Délai de réponse (erreur + rafraîchissement + réessai).
Rafraîchissement proactif (QueryInterceptor)
Utilise exp du JWT pour rafraîchir avant expiration. QueryInterceptor garantit un traitement séquentiel des requêtes.
Analyser le JWT pour extraire exp :
- Décoder la charge utile Base64.
- Analyser JSON, obtenir l'horodatage.
Avantage : pas d'erreurs 401 bloquantes. Inconvénient : file d'attente stricte, les requêtes parallèles sont bloquées.
Points clés à retenir
- Utiliser
Interceptorpour un rafraîchissement réactif avecCompleterpour la synchronisation. QueryInterceptorconvient au rafraîchissement proactif basé surexp.- Stocker les jetons dans un stockage isolé, utiliser un Dio séparé pour le rafraîchissement.
- Gérer les conditions de concurrence avec plusieurs 401.
- Le double jeton améliore la sécurité : accès court + rafraîchissement.
— Editorial Team
Aucun commentaire pour le moment.