Automatische JWT-Token-Aktualisierung in Dio: Interceptor und QueryInterceptor
Server überprüfen die Autorisierung über den Authorization-Header im Format <Auth-Schema> <Auth-Parameter>. Eine Middleware verarbeitet diesen Header für alle geschützten Endpunkte. Fehlen Daten oder sind sie ungültig, gibt sie 401 Unauthorized oder 403 Forbidden zurück.
Hauptschema:
- Basic: Base64-kodiertes Login:Passwort (
Authorization: Basic bG9naW46cGFzc3dvcmQ=). Geringe Sicherheit aufgrund einfacher Dekodierung. - Bearer: JWT-Token (
Authorization: Bearer <Token>). Unterstützt Ablaufzeiten, erfordert Aktualisierung.
JWT besteht aus Header (Algorithmus), Payload (Nutzerdaten, exp), Signatur (Server-Geheimnis). Format: {Header}.{Payload}.{Signatur} in Base64.
JWT-Struktur und Aktualisierung
Der Payload enthält exp (Ablaufzeit). Bei 401 fordern Clients eine Aktualisierung über einen geschützten Endpunkt ohne Middleware an.
Zwei-Token-Systeme:
- Access Token: Kurzlebig (Minuten), für API-Anfragen.
- Refresh Token: Langlebig, zum Generieren neuer Access-Tokens.
Strategien zum Umgang mit abgelaufenen Tokens
Abmelden (Einfachster Ansatz)
Bei 401 – Abmelden. Die Implementierung ist trivial, aber für Nutzer unpraktisch.
Vorteile:
- Minimaler Code.
Nachteile:
- Häufige erneute Anmeldungen.
- Nicht kompatibel mit Zwei-Token-Systemen.
Aktualisierung bei Fehler (Interceptor)
Implementiert über Interceptor in Dio. Fügt Token in onRequest hinzu, behandelt 401 in 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);
}
}
Einrichtung:
final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));
In onError für 401:
- Prüfe
_isRefreshing-Flag. - Wenn nicht – initiiere Aktualisierung über einen separaten Dio.
- Wartende Anfragen warten über
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;
}
}
Vollständige onError-Logik synchronisiert parallele Anfragen, wiederholt mit neuem Token.
Vorteile:
- Funktioniert mit Zwei-Token-Systemen.
- Keine externen Bibliotheken.
Nachteile:
- Wellenlast auf Server bei Massenwiederholung.
- Antwortverzögerung (Fehler + Aktualisierung + Wiederholung).
Proaktive Aktualisierung (QueryInterceptor)
Nutzt exp aus JWT, um vor Ablauf zu aktualisieren. QueryInterceptor stellt sequentielle Anfrageverarbeitung sicher.
JWT parsen, um exp zu extrahieren:
- Base64-Payload dekodieren.
- JSON parsen, Zeitstempel abrufen.
Vorteil: Keine blockierenden 401-Fehler. Nachteil: Strenge Warteschlange, parallele Anfragen werden blockiert.
Wichtige Erkenntnisse
- Verwende
Interceptorfür reaktive Aktualisierung mitCompleterzur Synchronisation. QueryInterceptoreignet sich für proaktive Aktualisierung basierend aufexp.- Speichere Tokens in isoliertem Speicher, verwende separaten Dio für Aktualisierung.
- Behandle Race Conditions mit mehreren 401-Fehlern.
- Zwei-Token-Systeme erhöhen Sicherheit: Kurzer Access + Refresh.
— Editorial Team
Noch keine Kommentare.