离线授权与宽限期
A7验证是在线验证服务,但真实用户环境常有断网、弱网。本页讲解如何在不改变后端的前提下,用已有字段(expire_at、Token 心跳)设计一套离线宽限体验。
服务端不提供「离线模式」开关
当前后端没有专门的离线授权端点。下面的方案全部建立在客户端对 expire_at 与心跳结果的本地缓存之上,属于客户端策略,不是新接口。
一、核心思路
- 登录成功后,把
data.expire_at(到期时间)与上次心跳时间缓存在本地(内存即可,敏感场景可加密落盘)。 - 每次心跳成功后刷新本地缓存的到期时间。
- 当检测不到网络时,不要立即判定软件不可用,进入「宽限期」:只要本地缓存的到期时间未过,就允许继续使用。
- 网络恢复后立刻补一次心跳;若心跳返回
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 + 机器码用本地密钥加密写入授权文件。每次启动时先校验授权文件里的机器码与当前机器一致、且未过期。
本地文件不是后端凭证
授权文件只是客户端缓存,服务端仍以实际到期时间和心跳结果为准。攻击者篡改本地时间或机器码绕过校验,只影响本地体验,无法突破服务端到期控制(重新联网心跳会被纠正)。
四、与心跳机制配合
详细心跳周期、离线识别与消息下发见 心跳保活机制。断网期间未发出的心跳会在恢复后补发,服务端按最近一次成功心跳判断在线状态。