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

Flutter中Token过期未自动跳转登录页问题求助

问题根源

当前启动页仅判断token是否存在,未验证其有效性;进入主页后也没有后续校验机制,导致过期token仍能留在主页。此外登录按钮存在多余的token清空代码,可能引发异常。

解决方案

1. 修复登录按钮的冗余代码

删除登录按钮中提前清空token的代码,避免登录失败时丢失原有有效token:

// 删掉以下两行冗余代码
// final prefs = await SharedPreferences.getInstance();
// prefs.setString(Constant.token, '');

2. 启动页添加token有效性校验

添加token有效性验证逻辑(以JWT为例,可解析过期时间;或调用后端校验接口):

第一步:添加JWT解析工具函数

import 'dart:convert';
import 'dart:typed_data';

bool isTokenValid(String token) {
  try {
    // 拆分JWT的三个部分
    final parts = token.split('.');
    if (parts.length != 3) return false;

    // 解码payload部分
    final normalizedPayload = base64Url.normalize(parts[1]);
    final payloadBytes = base64Url.decode(normalizedPayload);
    final payload = jsonDecode(utf8.decode(payloadBytes)) as Map<String, dynamic>;

    // 获取过期时间戳(单位:秒)
    final expTimestamp = payload['exp'] as int?;
    if (expTimestamp == null) return false;

    // 对比当前时间与过期时间
    final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
    return currentTime < expTimestamp;
  } catch (e) {
    // 解析失败则视为无效token
    return false;
  }
}

第二步:修改启动页跳转逻辑

Future<void> toLogin() async {
  Timer(
    const Duration(seconds: 3),
    () async {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      String? token = prefs.getString(Constant.token);
      bool isTokenActive = false;

      if (token != null) {
        // 验证token有效性
        isTokenActive = isTokenValid(token);
        // 若后端提供校验接口,可替换为接口调用:
        // isTokenActive = await userProvider.validateToken(token);
      }

      Navigator.pushReplacementNamed(
        context,
        (token != null && isTokenActive) ? AppRoute.mainRoute : AppRoute.loginRoute,
        arguments: token,
      );
    },
  );
}

3. 全局API拦截处理token过期

封装HTTP请求,统一捕获后端返回的token过期状态(如401状态码),自动清除token并跳转登录:

第一步:创建全局Navigator Key

在项目入口处定义全局导航键,确保在无context时也能跳转页面:

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

// 在MaterialApp中配置
MaterialApp(
  navigatorKey: navigatorKey,
  // ...其他配置
);

第二步:封装HTTP请求工具类

import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';

class HttpUtil {
  static Future<http.Response> request(
    String method,
    String url, {
    Map<String, String>? headers,
    dynamic body,
  }) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? token = prefs.getString(Constant.token);

    // 添加Authorization头
    headers ??= {};
    if (token != null) {
      headers['Authorization'] = 'Bearer $token';
    }

    http.Response response;
    switch (method.toLowerCase()) {
      case 'post':
        response = await http.post(Uri.parse(url), headers: headers, body: body);
        break;
      case 'get':
        response = await http.get(Uri.parse(url), headers: headers);
        break;
      // 可扩展其他请求方法
      default:
        throw Exception('Unsupported request method');
    }

    // 处理401(token过期/无效)
    if (response.statusCode == 401) {
      await prefs.remove(Constant.token);
      // 跳转登录页并清除所有栈页面
      navigatorKey.currentState?.pushNamedAndRemoveUntil(
        AppRoute.loginRoute,
        (route) => false,
      );
    }

    return response;
  }
}

第三步:替换原有API调用

将登录之外的API请求替换为封装后的工具类,例如主页的接口调用:

// 示例:获取用户信息
Future<User?> getUserInfo() async {
  try {
    final response = await HttpUtil.request('get', '${Constant.baseURL}/user_info');
    if (response.statusCode == 200) {
      return User.fromJson(jsonDecode(response.body));
    }
    return null;
  } catch (e) {
    print(e);
    return null;
  }
}

4. 主页初始化时校验token(可选)

在主页的initState中添加token校验,确保进入主页时token仍有效:

@override
void initState() {
  super.initState();
  _verifyTokenOnEntry();
}

Future<void> _verifyTokenOnEntry() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String? token = prefs.getString(Constant.token);

  if (token != null && !isTokenValid(token)) {
    await prefs.remove(Constant.token);
    Navigator.pushNamedAndRemoveUntil(
      context,
      AppRoute.loginRoute,
      (route) => false,
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:55:26