Automatická obnova JWT tokenů v Dio: Interceptor a QueryInterceptor
Servery ověřují autorizaci prostřednictvím hlavičky Authorization ve formátu <auth-scheme> <auth-parameters>. Middleware zpracovává tuto hlavičku pro všechny chráněné koncové body. Při absenci nebo neplatnosti dat se vrací 401 Unauthorized nebo 403 Forbidden.
Základní schémata:
- Basic: Base64 kódované přihlašovací údaje (
Authorization: Basic bG9naW46cGFzc3dvcmQ=). Nízká bezpečnost kvůli snadnému dekódování. - Bearer: JWT token (
Authorization: Bearer <Token>). Podporuje časovou platnost, vyžaduje obnovu.
JWT se skládá z Header (algoritmus), Payload (uživatelská data, exp), Signature (tajný klíč serveru). Formát: {Header}.{Payload}.{Signature} v Base64.
Struktura JWT a obnova
Payload obsahuje exp (čas vypršení platnosti). Při 401 klienti žádají o refresh prostřednictvím chráněného koncového bodu bez middleware.
Systémy s dvojitým tokenem:
- Access Token: Krátká platnost (minuty), pro API požadavky.
- Refresh Token: Dlouhá platnost, pro generování nového Access tokenu.
Strategie zpracování vypršených tokenů
Odhlášení (nejjednodušší přístup)
Při 401 — logout. Implementace je triviální, ale nepohodlná pro uživatele.
Výhody:
- Minimální kód.
Nevýhody:
- Časté opětovné přihlašování.
- Nekompatibilní s dvojitým tokenem.
Obnova po chybě (Interceptor)
Implementuje se pomocí Interceptor v Dio. Přidává token v onRequest, zpracovává 401 v 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);
}
}
Připojení:
final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));
V onError pro 401:
- Zkontrolujeme příznak
_isRefreshing. - Pokud ne — spustíme obnovu pomocí samostatného Dio.
- Fronta požadavků čeká přes
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;
}
}
Úplná logika onError synchronizuje paralelní požadavky, retry s novým tokenem.
Výhody:
- Funguje s dvojitým tokenem.
- Bez externích knihoven.
Nevýhody:
- Vlnové zatížení serveru při hromadném retry.
- Zpoždění odpovědi (chyba + refresh + retry).
Proaktivní obnova (QueryInterceptor)
Používá exp z JWT pro obnovu před vypršením platnosti. QueryInterceptor zajišťuje sekvenční zpracování požadavků.
Rozbor JWT pro získání exp:
- Dekódovat Base64 Payload.
- Parsovat JSON, získat timestamp.
Výhoda: žádné blokující chyby 401. Nevýhoda: pevná fronta, paralelní požadavky jsou blokovány.
Co je důležité
- Použijte
Interceptorpro reaktivní obnovu sCompleterpro synchronizaci. QueryInterceptorje vhodný pro proaktivní refresh podleexp.- Ukládejte tokeny v izolovaném úložišti, použijte samostatný Dio pro refresh.
- Zpracujte race conditions při více 401.
- Dvojitý token zvyšuje bezpečnost: krátký access + refresh.
— Editorial Team
Zatím žádné komentáře.