返回首页

在 Dio 中更新 JWT:Interceptor 方法

本文涵盖 Dio 中的 JWT 令牌刷新机制:使用 Completer 的响应式 Interceptor、按 exp 的主动 QueryInterceptor。Basic/Bearer 方案比较、双令牌架构、生产代码示例。

自动刷新 Dio 令牌:从理论到代码
Advertisement 728x90

Dio中自动刷新JWT令牌:拦截器与查询拦截器详解

服务器通过Authorization头验证授权,格式为<认证方案> <认证参数>。中间件为所有受保护端点处理此头信息。如果数据缺失或无效,则返回401未授权或403禁止访问。

主要方案:

  • Basic:Base64编码的登录名:密码(Authorization: Basic bG9naW46cGFzc3dvcmQ=)。安全性低,易于解码。
  • Bearer:JWT令牌(Authorization: Bearer <令牌>)。支持过期,需要刷新。

JWT由头部(算法)、载荷(用户数据、exp)、签名(服务器密钥)组成。格式为Base64编码的{头部}.{载荷}.{签名}

Google AdInline article slot

JWT结构与刷新机制

载荷包含exp(过期时间)。当收到401时,客户端通过一个不受中间件保护的端点请求刷新令牌。

双令牌系统:

  • 访问令牌:短期有效(几分钟),用于API请求。
  • 刷新令牌:长期有效,用于生成新的访问令牌。

处理过期令牌的策略

登出(最简单方法)

收到401时——登出。实现简单,但对用户不便。

Google AdInline article slot

优点:

  • 代码量最小。

缺点:

  • 频繁重新登录。
  • 不兼容双令牌系统。

错误时刷新(拦截器)

通过Dio的Interceptor实现。在onRequest中添加令牌,在onError中处理401错误。

Google AdInline article slot
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);
  }
}

设置:

final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));

onError中处理401:

  • 检查_isRefreshing标志。
  • 如果未刷新——通过单独的Dio实例启动刷新。
  • 排队请求通过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;
  }
}

完整的onError逻辑同步并行请求,使用新令牌重试。

优点:

  • 适用于双令牌系统。
  • 无需外部库。

缺点:

  • 大量重试可能导致服务器负载波动。
  • 响应延迟(错误 + 刷新 + 重试)。

主动刷新(查询拦截器)

使用JWT中的exp在过期前刷新。QueryInterceptor确保顺序处理请求。

解析JWT提取exp

  • 解码Base64载荷。
  • 解析JSON,获取时间戳。

优点:避免阻塞性401错误。缺点:严格队列,并行请求被阻塞。

关键要点

  • 使用Interceptor进行响应式刷新,配合Completer同步。
  • QueryInterceptor适合基于exp的主动刷新。
  • 将令牌存储在隔离存储中,使用单独的Dio实例进行刷新。
  • 处理多个401时的竞态条件。
  • 双令牌增强安全性:短期访问 + 刷新令牌。

— Editorial Team

Advertisement 728x90

继续阅读