欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

请添加图片描述

前言

在开发 OpenHarmony 移动应用时, Access Token 通常具有较短的有效期(如 3600s)。一旦过期,直接报错会导致用户请求失败,频繁登出,体验极差。

fresh 库提供了“无感刷新”的抽象模型。它将 Token 的存储、读取、验证、刷新这四个环节高度解耦,让开发者能像配置乐高积木一样搭建认证系统。

一、核心工作流程

返回 401

新 Token (包含 expiresAt)

刷新失败

Flutter 请求 (Old Token)

API 服务器

Fresh 拦截器

认证中心 (刷新接口)

持久化存储 (鸿蒙本地)

重发原业务请求 (New Token)

用户无感知,请求成功

清理状态,跳转登录页

二、核心 API 实战

2.1 定义带生命周期的 Token

一个严谨的令牌模型应包含 expiresAt,以便客户端判定是否需要主动刷新,并方便 UI 展示倒计时。

class MyToken {
  final String accessToken;
  final String refreshToken;
  final DateTime expiresAt; // 💡 增加过期时间字段
  
  MyToken({
    required this.accessToken, 
    required this.refreshToken, 
    required this.expiresAt
  });

  // 💡 辅助属性:判定是否已失效
  bool get isExpired => DateTime.now().isAfter(expiresAt);
}

在这里插入图片描述

2.2 配置 Fresh 核心实例

final fresh = Fresh<MyToken>(
  tokenHeader: (token) => {'Authorization': 'Bearer ${token.accessToken}'},
  tokenStorage: InMemoryTokenStorage<MyToken>(), // 💡 建议对接鸿蒙持久化首选项
  refreshToken: (token, client) async {
    // 💡 无感转化的核心:在这里调用后端刷新 API
    print("🌱 正在申请换发新令牌...");
    final response = await client.post('/auth/refresh', data: {'refresh': token?.refreshToken});
    
    return MyToken(
      accessToken: response.data['token'],
      refreshToken: response.data['refresh'],
      expiresAt: DateTime.now().add(const Duration(hours: 1)), // 模拟 1 小时有效期
    );
  },
);

在这里插入图片描述

2.3 身份验证状态流 (authenticationStatus)

Fresh 提供了响应式的状态流,在鸿蒙上可极大简化路由逻辑:

  • authenticated: 已登录,进入主页。
  • unauthenticated: 未登录或刷新失败,跳转登录。

在这里插入图片描述

三、OpenHarmony 平台适配

3.1 跨进程 Token 共享

在鸿蒙的元服务或多 HAP 环境下,建议利用 PersistentStoreCommonEventManager 广播 Token 变更,虽然 Fresh 基库是 Dart 层的,但其 tokenStorage 接口是完美的挂载点。

3.2 刷新锁机制 (Refresh Lock)

fresh 内部实现了“并发竞争锁”。当鸿蒙应用同时发起 10 个业务请求遇到过期时,它能保证仅触发 1 次刷新请求,其余 9 个请求会自动挂载到等待队列中,待刷新完成后带上新 Token 批量重放。

四、完整实战示例:鸿蒙无感登录拦截器

本示例展示了如何实现一个高可靠性的认证管理页面,并模拟完整的刷新闭环。

import 'package:flutter/material.dart';
import 'package:fresh_dio/fresh_dio.dart';

class FreshBasicDemo extends StatefulWidget {
  
  _FreshBasicDemoState createState() => _FreshBasicDemoState();
}

class _FreshBasicDemoState extends State<FreshBasicDemo> {
  late Fresh<MyToken> _fresh;
  final List<String> _logs = [];

  
  void initState() {
    super.initState();
    // 1. 初始化 Fresh
    _fresh = Fresh<MyToken>(
      tokenHeader: (token) => {'Authorization': 'Bearer ${token.accessToken}'},
      tokenStorage: InMemoryTokenStorage<MyToken>(),
      refreshToken: (token, client) async {
        _addLog("🌱 正在通过 Refresh Token 获取新令牌...");
        await Future.delayed(Duration(seconds: 1)); // 模拟网络延迟
        return MyToken("new_access_token", "new_refresh_token");
      },
    );
  }

  void _addLog(String msg) => setState(() => _logs.insert(0, msg));

  void _simulateExpiredRequest() async {
    _addLog("📡 发送业务请求...");
    if (await _fresh.token == null) {
      _addLog("❌ 请求失败:请先点击登录");
      return;
    }

    _addLog("💡 模拟业务请求返回 401... Fresh 拦截器介入");
    
    // 💡 模拟无感刷新流程
    try {
      final currentToken = await _fresh.token;
      // 注意:实际项目中此步骤由拦截器内部自动触发
      final newToken = await _fresh.refreshToken!(currentToken, null);
      await _fresh.setToken(newToken);
      
      _addLog("✅ 令牌刷新成功!");
      _addLog("▶️ 自动重试原业务请求... ✨ 请求重试成功!");
    } catch (e) {
      _addLog("❌ 刷新失败: $e");
    }
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: () async {
            await _fresh.setToken(MyToken("initial_access", "initial_refresh"));
            _addLog("👤 模拟登录成功");
          },
          child: Text("1. 模拟登录"),
        ),
        ElevatedButton(
          onPressed: _simulateExpiredRequest,
          child: Text("2. 模拟过期请求 (触发无感刷新)"),
        ),
        Expanded(
          child: ListView.builder(
            itemCount: _logs.length,
            itemBuilder: (context, i) => Text(_logs[i]),
          ),
        ),
      ],
    );
  }
}

在这里插入图片描述

五、总结

fresh 解决了身分验证中最繁琐的状态流转问题。通过将 TokenStorage 与鸿蒙原生存储绑定,你可以构建出具有“持久化登录”能力的工业级 App。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐