跳转到正文
YGJoon 技术博客

iOS Keychain 会话隔离:请求快照与迟到响应处理

发布于:
·694 字 · 约 2 分钟·作者:
通过安全存储、会话代次和请求快照,避免账号切换时迟到的异步响应污染当前用户界面。
iOS Keychain 会话隔离:请求快照与迟到响应处理文章封面
目录

示例代码均为匿名化改写,用于说明模式;Keychain 读写细节需按应用的安全策略实现。

凭据与界面状态分开

共享认证状态负责当前用户、令牌和会话版本;独立的存储层负责 Keychain 读写。凭据使用设备解锁后可访问、且不迁移到其他设备的保护级别。视图读取会话状态,不直接操作 Security API。

服务端判定某个令牌失效时,应先确认失败请求使用的令牌仍属于当前会话。否则一个旧请求可能在新用户登录之后返回,再错误地清除新会话。

为什么需要会话快照

检查“当前已登录”不足以判断请求归属。请求发出后,用户可能退出并登录另一账号;旧请求返回时,登录状态依然为真,但响应数据属于旧用户。

请求开始时记录会话版本和身份快照,完成后再比较。页面请求 ID 可以拦截同一页面上较晚发出的查询;会话版本则拦截跨账号的迟到结果。两项检查共同决定响应是否仍能更新界面。

struct SessionSnapshot: Equatable, Sendable {
    let accountID: UUID
    let generation: UInt64
}

actor SessionStore {
    private var current: SessionSnapshot?

    func snapshot() -> SessionSnapshot? { current }

    func replaceAccount(with accountID: UUID) {
        let nextGeneration = (current?.generation ?? 0) + 1
        current = SessionSnapshot(
            accountID: accountID,
            generation: nextGeneration
        )
    }

    func isCurrent(_ snapshot: SessionSnapshot) -> Bool {
        current == snapshot
    }
}

账号切换时,仅检查“仍然已登录”不足以判定迟到响应的归属;请求应同时比对账号标识和会话代次。

退出失败也要保持状态一致

如果删除安全存储失败,应用不应显示退出成功,却在下次启动时恢复旧凭据。可以恢复先前的内存会话并提示失败,或用独立失效标记阻止已判无效的令牌被恢复;具体选择要与账号状态模型一致。

SecItemDelete 成功后才能把界面切到退出状态。删除失败时保留当前内存会话并提示可恢复的错误,避免应用显示已退出、下次启动却恢复旧凭据。

实践要点


分享这篇文章:


相关文章

上一篇
iOS 支付回跳对账:待处理记录持久化与服务端确认
下一篇
SwiftUI 详情页并发加载:请求竞态与导航状态保留