LESSON 38 / 578 分钟

Keychain:安全保存登录凭证

Keychain 是系统管理的小型敏感数据存储。它解决凭证放在哪里,不负责判断你的服务器是否仍接受该凭证。

用你的前端经验理解

可以类比一个受系统保护的凭证仓库。UserDefaults 像偏好存储,Keychain 不是加密版业务数据库,也不是登录服务。

为什么需要它

登录凭证需要在应用重启后可恢复,又不能像普通偏好那样随意保存。Keychain 提供系统管理的敏感条目存储,但它不是远端身份认证服务。读取到 refresh token 后,仍要向业务后端换取会话;设备当前无法访问某个条目,也不等于服务端已经撤销账号。

它是怎样工作的

常见 generic password 条目通过 class、service 和 account 等属性确定身份。保存需要处理首次添加与已存在更新,读取要区分不存在、格式不符和系统拒绝。把 OSStatus 映射为可判断的领域错误,比统一返回 nil 更可靠。不同账号应有不同定位条件,避免切换账号时读到旧身份的凭证。

把关键概念连起来

1

对象与操作

常用 generic password item,以 service 和 account 等属性定位。SecItemAdd、SecItemCopyMatching、SecItemUpdate、SecItemDelete 分别处理增、查、改、删。查询条件要足够精确。

2

错误与生命周期

返回值是 OSStatus。区分成功、条目不存在、重复条目和当前不可访问;重复时按明确策略更新,失败时不要伪装为“用户尚未登录”。

3

凭证策略

业务 refresh token 可保存在 Keychain;短期 access token 可按需要留在内存。退出登录时清理本账号对应条目并撤销可撤销的服务端会话,不假定卸载会完成清理。

Swift · 示例片段
import Foundationimport Security// 函数内片段:读取这个 service/account 的一条凭证let query: [String: Any] = [    kSecClass as String: kSecClassGenericPassword,    kSecAttrService as String: "com.example.native.session",    kSecAttrAccount as String: "demo-user",    kSecReturnData as String: true,    kSecMatchLimit as String: kSecMatchLimitOne]var item: CFTypeRef?let status = SecItemCopyMatching(query as CFDictionary, &item)// status == errSecSuccess:再检查 item 是否为 Data// errSecItemNotFound:没有条目;其他状态应分别处理// 不要记录 item 或 token 原文
  • 查询中的 service 与 account 共同收窄条目范围;返回数据与匹配数量控制需要取回什么。
  • SecItemCopyMatching 返回 OSStatus。只有成功后才能按预期类型解释 item;不存在与暂时不可访问必须分别处理。

用于理解当前概念的代码片段;部分示例需要放入对应工程与作用域,并补齐上下文。

阅读 App 的登录恢复

启动时读取 refresh token,向自己的后端请求新会话。若服务端明确返回已撤销,就清理该账号凭证并进入登录流程;若只是断网,应保留离线内容并显示连接状态。

实现一个可审查的 TokenStore

  1. save 在条目不存在时添加,重复条目走更新;查询范围限制到当前 service/account,不进行全组覆盖。
  2. read 返回凭证、无条目或访问错误三类结果。对损坏 Data 的解码失败要单独处理,不把它记录成明文日志。
  3. 退出时删除本账号条目,并按后端能力撤销会话;失败时记录安全错误信息,避免界面宣称全部清理完成。

这里需要你亲自判断

不要输出 token 原文,也不要在删除时使用过宽查询误删同组的其他凭证;能读取旧 token 不代表旧会话仍有效。

做一个小练习

为一个 token store 定义 save/read/delete 接口;用虚构字符串验证首次保存、更新、读取不存在和退出清理。

  1. 用虚构 token 测试首次保存、替换、读取不存在、删除后读取与另一个账号不受影响。
  2. 定义断网与后端明确撤销时不同的登录恢复行为。
展开参考思路与验收标准

无条目可以进入登录,暂时不可访问可等待合适时机,后端明确撤销才按会话策略清理。测试应只使用演示凭证,检查删除条件比检查“返回成功”更重要。

Keychain 中还能读到 token,是否证明账号当前仍已登录?

继续查阅官方资料
Apple Developer 官方资料

本课聚焦核心认知。具体 API、系统要求与发布政策,以当前官方文档和工程验证为准。

答对理解题后即可标记完成