Skip to content

离线授权与宽限期

A7验证是在线验证服务,但真实用户环境常有断网、弱网。本页讲解如何在不改变后端的前提下,用已有字段(expire_at、Token 心跳)设计一套离线宽限体验。

服务端不提供「离线模式」开关

当前后端没有专门的离线授权端点。下面的方案全部建立在客户端对 expire_at 与心跳结果的本地缓存之上,属于客户端策略,不是新接口。

一、核心思路

  1. 登录成功后,把 data.expire_at(到期时间)与上次心跳时间缓存在本地(内存即可,敏感场景可加密落盘)。
  2. 每次心跳成功后刷新本地缓存的到期时间。
  3. 当检测不到网络时,不要立即判定软件不可用,进入「宽限期」:只要本地缓存的到期时间未过,就允许继续使用。
  4. 网络恢复后立刻补一次心跳;若心跳返回 1005 / 1006 / 1007,则终止使用。

二、宽限期设计

阶段条件行为
正常网络可用,心跳成功正常使用,刷新缓存
弱网/断网本地到期时间未过 + 宽限未用尽允许使用,提示「离线模式(剩余宽限 x 分钟)」
宽限耗尽断网超过宽限(如 30 分钟)暂停核心功能,提示联网
恢复后失效心跳返回 1005/1006/1007立即终止,要求重新登录
python
import time

GRACE_SECONDS = 30 * 60  # 30 分钟宽限

class OfflineGuard:
    def __init__(self):
        self.expire_at = 0      # 本地缓存的到期时间戳
        self.last_heartbeat = 0

    def on_login(self, expire_at_str):
        self.expire_at = _parse(expire_at_str)
        self.last_heartbeat = time.time()

    def allow_use(self) -> bool:
        now = time.time()
        # 已过期直接拒绝
        if now > self.expire_at:
            return False
        # 离线且超过宽限 → 拒绝
        if now - self.last_heartbeat > GRACE_SECONDS:
            return False
        return True

三、本地授权文件(可选)

对必须长期离线的高安全要求场景,可在「在线激活成功」时,把 token + expire_at + 机器码用本地密钥加密写入授权文件。每次启动时先校验授权文件里的机器码与当前机器一致、且未过期。

本地文件不是后端凭证

授权文件只是客户端缓存,服务端仍以实际到期时间和心跳结果为准。攻击者篡改本地时间或机器码绕过校验,只影响本地体验,无法突破服务端到期控制(重新联网心跳会被纠正)。

四、与心跳机制配合

详细心跳周期、离线识别与消息下发见 心跳保活机制。断网期间未发出的心跳会在恢复后补发,服务端按最近一次成功心跳判断在线状态。

相关链接

A7验证 · 软件授权与网络验证平台