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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:45:17