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

移动端JWT令牌expiresAt时间不一致问题及expiresIn实现咨询

问题描述

我在APP中使用accessToken和refreshToken,已实现标准OAuth2令牌流程:

+--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

当前服务器返回的令牌结构如下:

"token": "eyJhbGciOiJIUzI1NiI....",
"refreshToken": "91792ee6-5cf4-45e6-96a5-4e5c47f4a601-188318b9-1591-41d7-9ba2-3d1b11f68383",
"expiresAt": "2022-08-23T09:40:24Z"

现在客户端通过expiresAt结合设备时间判断accessToken是否过期,存在两个核心问题:

  • 设备时间与服务器不一致时(比如实际时间14:00,设备显示13:30,令牌expiresAt为13:50,refreshToken过期时间13:51),客户端误判令牌有效,发起请求后服务器返回401错误
  • 用户修改设备时间可让accessToken永不过期

想要改用expiresIn替代expiresAt,求具体实现方案。

实现方案

1. 服务器端调整令牌返回结构

将返回的expiresAt字段替换为expiresIn,字段值为accessToken的有效期时长(单位:秒),比如accessToken有效期为3600秒,则返回结构改为:

"token": "eyJhbGciOiJIUzI1NiI....",
"refreshToken": "91792ee6-5cf4-45e6-96a5-4e5c47f4a601-188318b9-1591-41d7-9ba2-3d1b11f68383",
"expiresIn": 3600

注意:如果是JWT令牌,本身payload里会包含exp(过期时间戳)和iat(签发时间戳),可以直接从JWT中解析出expiresIn(exp - iat),服务器也可以额外返回该字段方便客户端直接使用。

2. 客户端核心逻辑实现

  • 存储令牌时记录本地接收时间:当客户端收到服务器返回的令牌时,立即记录当前设备的本地时间戳(毫秒级),和token、refreshToken、expiresIn一起存储。
  • 判断令牌是否过期:每次发起请求前,计算当前本地时间戳与存储的接收时间戳的差值,若差值小于expiresIn * 1000(转成毫秒),则认为令牌有效;反之则判定为过期,触发刷新流程。
    示例伪代码:
    // 存储令牌时
    const tokenData = {
      token: "eyJhbGciOiJIUzI1NiI....",
      refreshToken: "91792ee6-5cf4-45e6-96a5-4e5c47f4a601-188318b9-1591-41d7-9ba2-3d1b11f68383",
      expiresIn: 3600,
      receivedTimestamp: Date.now() // 本地接收时的时间戳(毫秒)
    };
    saveToLocalStorage(tokenData);
    
    // 判断是否过期
    const storedTokenData = getFromLocalStorage();
    const currentTimestamp = Date.now();
    const elapsedTime = currentTimestamp - storedTokenData.receivedTimestamp;
    const isTokenExpired = elapsedTime >= storedTokenData.expiresIn * 1000;
    

3. 异常情况处理

  • 设备时间被修改:如果用户修改设备时间,客户端计算的elapsedTime会出现偏差,但服务器端会严格基于自身时间校验令牌有效性,若客户端误判令牌有效发起请求,服务器会返回401,此时客户端需立即触发刷新流程。
  • 刷新令牌过期:服务器返回刷新令牌时可附带refreshExpiresIn字段,客户端用同样的方式(记录接收时间+计算差值)判断刷新令牌是否过期,若过期则直接引导用户重新登录。

4. 优化建议

  • 提前刷新令牌:不要等令牌完全过期再刷新,比如在令牌剩余有效期的最后10%(如360秒)就发起刷新请求,避免因网络延迟导致请求失败。
  • JWT令牌双重校验:如果使用JWT,客户端可以解析JWT的exp字段,结合本地接收时间做双重校验,提升逻辑严谨性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:48:46