You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现AccessToken与RefreshToken后台管理任务咨询

实现Flutter令牌(AccessToken/RefreshToken)自动管理方案

核心思路

不需要依赖后台持续运行任务(Flutter后台任务在iOS/Android上有严格限制,且完全没必要),而是通过存储AccessToken的过期时间戳来实现校验逻辑:

  • 获取令牌时同步保存过期时间(当前时间+1小时)
  • 每次启动应用/发起请求前,对比当前时间与过期时间,自动判断是否需要刷新令牌

具体实现步骤

1. 封装令牌管理类

基于flutter_secure_storage封装统一的令牌读写、校验、刷新逻辑:

import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:async';

class AuthTokenManager {
  final FlutterSecureStorage _storage = const FlutterSecureStorage();
  
  // 存储键定义
  static const String _keyAccessToken = 'access_token';
  static const String _keyRefreshToken = 'refresh_token';
  static const String _keyExpiresAt = 'expires_at';

  // 保存令牌及过期时间
  Future<void> saveTokens({
    required String accessToken,
    required String refreshToken,
  }) async {
    // 计算1小时后的时间戳
    final expiresAt = DateTime.now().add(const Duration(hours: 1)).millisecondsSinceEpoch;
    await Future.wait([
      _storage.write(key: _keyAccessToken, value: accessToken),
      _storage.write(key: _keyRefreshToken, value: refreshToken),
      _storage.write(key: _keyExpiresAt, value: expiresAt.toString()),
    ]);
  }

  // 获取可用AccessToken,自动处理过期刷新
  Future<String?> getValidAccessToken() async {
    final accessToken = await _storage.read(key: _keyAccessToken);
    final expiresAtStr = await _storage.read(key: _keyExpiresAt);
    final refreshToken = await _storage.read(key: _keyRefreshToken);

    // 无令牌直接返回null,引导登录
    if (accessToken == null || expiresAtStr == null || refreshToken == null) {
      return null;
    }

    final expiresAt = DateTime.fromMillisecondsSinceEpoch(int.parse(expiresAtStr));
    final now = DateTime.now();

    // 提前30秒刷新(避免请求时刚好过期)
    if (now.isBefore(expiresAt.subtract(const Duration(seconds: 30)))) {
      return accessToken;
    } else {
      // 调用刷新接口获取新令牌
      final newTokens = await _refreshToken(refreshToken);
      if (newTokens != null) {
        await saveTokens(accessToken: newTokens.accessToken, refreshToken: newTokens.refreshToken);
        return newTokens.accessToken;
      } else {
        // 刷新失败,清除本地令牌
        await clearTokens();
        return null;
      }
    }
  }

  // 调用后端刷新令牌接口(需根据你的API逻辑实现)
  Future<({String accessToken, String refreshToken})?> _refreshToken(String refreshToken) async {
    // 示例逻辑,替换为你的真实请求:
    // final response = await http.post(
    //   Uri.parse('https://your-api.com/auth/refresh'),
    //   body: {'refresh_token': refreshToken},
    // );
    // if (response.statusCode == 200) {
    //   final data = jsonDecode(response.body);
    //   return (
    //     accessToken: data['access_token'],
    //     refreshToken: data['refresh_token'] ?? refreshToken,
    //   );
    // }
    return null;
  }

  // 清除所有令牌
  Future<void> clearTokens() async {
    await Future.wait([
      _storage.delete(key: _keyAccessToken),
      _storage.delete(key: _keyRefreshToken),
      _storage.delete(key: _keyExpiresAt),
    ]);
  }
}

2. 在业务中使用

在应用启动或网络请求前调用getValidAccessToken()获取有效令牌:

final tokenManager = AuthTokenManager();

// 示例:发起API请求前获取令牌
Future<void> fetchUserData() async {
  final accessToken = await tokenManager.getValidAccessToken();
  
  if (accessToken == null) {
    // 跳转到登录页面
    return;
  }

  // 携带令牌发起请求
  // final response = await http.get(
  //   Uri.parse('https://your-api.com/user'),
  //   headers: {'Authorization': 'Bearer $accessToken'},
  // );
}

关键注意事项

  • 提前刷新机制:设置提前30秒刷新,避免请求时令牌刚好过期导致失败
  • RefreshToken有效期:确保后端返回的RefreshToken有效期长于AccessToken(比如7天),减少用户登录频率
  • 错误处理:刷新令牌失败时,必须清除本地令牌,引导用户重新登录
  • 安全保障:依赖flutter_secure_storage的加密存储,令牌不会明文暴露

内容的提问来源于stack exchange,提问作者Konstantinos Rotsidis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:05:23