Flutter中为SharedPreferences存储的Access Token设置1小时过期时间
实现Flutter中Access Token的自动过期清理
核心思路
要实现Token每1小时自动清理,不能只存储Token本身,需要同时记录Token的过期时间,结合「定时任务主动清理」和「使用/启动时校验清理」两种方式,避免单纯依赖定时任务被系统回收的问题。
具体实现步骤
1. 封装SharedPreferences操作工具类
将Token的存储、获取、校验、清理逻辑封装成工具方法,方便复用:
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:async'; import 'package:flutter/material.dart'; class TokenManager { static Timer? _tokenExpiryTimer; // 存储Token并设置过期时间 static Future<void> saveAccessToken(String token) async { final prefs = await SharedPreferences.getInstance(); // 计算1小时后的时间戳(毫秒) final expiryTimestamp = DateTime.now().add(const Duration(hours: 1)).millisecondsSinceEpoch; await prefs.setString('access_token', token); await prefs.setInt('token_expiry', expiryTimestamp); // 取消之前的定时器,避免重复触发 _tokenExpiryTimer?.cancel(); // 启动1小时后的自动清理定时器 _tokenExpiryTimer = Timer(const Duration(hours: 1), () async { await _clearExpiredToken(); }); } // 获取有效Token(自动校验过期) static Future<String?> getValidAccessToken() async { final isExpired = await _checkTokenExpiry(); if (isExpired) { await _clearExpiredToken(); return null; } final prefs = await SharedPreferences.getInstance(); return prefs.getString('access_token'); } // 校验Token是否过期 static Future<bool> _checkTokenExpiry() async { final prefs = await SharedPreferences.getInstance(); final expiryTimestamp = prefs.getInt('token_expiry'); if (expiryTimestamp == null) return true; final currentTimestamp = DateTime.now().millisecondsSinceEpoch; return currentTimestamp >= expiryTimestamp; } // 清理过期的Token和过期时间记录 static Future<void> _clearExpiredToken() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('access_token'); await prefs.remove('token_expiry'); // 清理后取消定时器 _tokenExpiryTimer?.cancel(); } }
2. 启动时校验清理
在App启动时主动校验Token是否过期,避免重启后残留过期Token:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 启动时自动清理过期Token await TokenManager._checkTokenExpiry().then((isExpired) { if (isExpired) TokenManager._clearExpiredToken(); }); runApp(const MyApp()); }
3. 使用Token前的校验
每次需要使用Token发起请求前,调用getValidAccessToken()获取,确保拿到的是未过期的Token:
// 示例:发起API请求时获取Token Future<void> fetchData(BuildContext context) async { final token = await TokenManager.getValidAccessToken(); if (token == null) { // Token已过期,跳转到登录页 Navigator.pushReplacementNamed(context, '/login'); return; } // 携带Token发起请求 // ... }
注意事项
- 单纯的
Timer在App退到后台后可能被系统回收,因此启动校验和使用前校验是必须的兜底逻辑,确保过期Token不会被误用。 - 如果需要更稳定的后台定时任务(比如App后台时也能触发清理),可以额外引入专门的后台任务包,但基于
shared_preferences的方案已经能覆盖绝大多数前端场景的需求。
内容的提问来源于stack exchange,提问作者MIT SHAH
相关产品推荐
相关产品推荐

