Actualización Automática de Tokens JWT en Dio: Interceptor y QueryInterceptor
Los servidores verifican la autorización mediante el encabezado Authorization en el formato <esquema-autenticación> <parámetros-autenticación>. El middleware procesa este encabezado para todos los endpoints protegidos. Si faltan datos o son inválidos, devuelve 401 No Autorizado o 403 Prohibido.
Principales esquemas:
- Basic: Login:contraseña codificado en Base64 (
Authorization: Basic bG9naW46cGFzc3dvcmQ=). Baja seguridad debido a la fácil decodificación. - Bearer: Token JWT (
Authorization: Bearer <Token>). Admite expiración, requiere actualización.
JWT consta de Encabezado (algoritmo), Carga útil (datos de usuario, exp), Firma (secreto del servidor). Formato: {Encabezado}.{Carga útil}.{Firma} en Base64.
Estructura JWT y Actualización
La carga útil contiene exp (tiempo de expiración). Ante un 401, los clientes solicitan una actualización mediante un endpoint protegido sin middleware.
Sistemas de doble token:
- Token de Acceso: De corta duración (minutos), para solicitudes API.
- Token de Actualización: De larga duración, para generar nuevos tokens de acceso.
Estrategias para Manejar Tokens Expirados
Cerrar Sesión (Enfoque Más Simple)
Ante 401 — cerrar sesión. La implementación es trivial pero inconveniente para los usuarios.
Ventajas:
- Código mínimo.
Desventajas:
- Reingresos frecuentes.
- Incompatible con doble token.
Actualizar en Error (Interceptor)
Implementado mediante Interceptor en Dio. Agrega token en onRequest, maneja 401 en 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);
}
}
Configuración:
final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));
En onError para 401:
- Verificar bandera
_isRefreshing. - Si no está activa — iniciar actualización mediante un Dio separado.
- Las solicitudes en cola esperan mediante
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 lógica completa de onError sincroniza solicitudes paralelas, reintenta con nuevo token.
Ventajas:
- Funciona con doble token.
- Sin bibliotecas externas.
Desventajas:
- Carga en oleadas al servidor con reintentos masivos.
- Retraso en respuesta (error + actualización + reintento).
Actualización Proactiva (QueryInterceptor)
Utiliza exp del JWT para actualizar antes de la expiración. QueryInterceptor asegura procesamiento secuencial de solicitudes.
Analizar JWT para extraer exp:
- Decodificar Carga útil Base64.
- Analizar JSON, obtener marca de tiempo.
Ventaja: sin errores 401 bloqueantes. Desventaja: cola estricta, solicitudes paralelas bloqueadas.
Conclusiones Clave
- Usar
Interceptorpara actualización reactiva conCompleterpara sincronización. QueryInterceptorse adapta a actualización proactiva basada enexp.- Almacenar tokens en almacenamiento aislado, usar un Dio separado para actualización.
- Manejar condiciones de carrera con múltiples 401.
- Doble token mejora seguridad: acceso corto + actualización.
— Editorial Team
Aún no hay comentarios.