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
相关产品推荐
相关产品推荐

