# 4. 使用 Keychain 存储登录态需要注意的一个坑

**作者**: [KANGZUBIN](https://weibo.com/kangzubin)

今天要讨论的这个问题你可能永远都不会遇到，而且绝大部分情况下你很难在开发中事先预料到它未来可能会发生，但是一旦不幸发生了，可能就是一个很严重的线上问题，惨痛教训。

我们通常会在 `Keychain`（钥匙串）中存储一些密码、用户登录态等敏感数据，一是可以提高保存数据的安全性；二是当用户卸载 App 后重新安装，可以自动登录保留上次的登录态；三是同一开发者账号下的不同 App，如果是采用同一套账户体系，就可以通过 `Keychain Groups` 共享登录态。

我们的 App 之前都是只把用户的登录态保存在 `Keychain` 中，并在 App 启动时去读取它，这一直也都没什么问题。前一段时间我们的 App 由于业务合规的原因审核被拒，按照苹果的要求不得不把 App 从公司的 A 开发者账号转让到 B 开发者账号下（公司旗下有很多不同主体的开发者账号），转让过程很顺利，但发版后短时间内收到大面积的用户反馈说，更新新版本后提示“登录失效，需要重新登录”。

原因很容易就可以猜到，App 从 A 转让到 B，就无法读取保存在 A 账号下的 `Keychain` 数据了，用户更新版本覆盖安装后，打开 App 也就无法获取之前的登录态了。

而且对于这种已经发生的问题，我们似乎也没有什么有效的补救措施，临时加急再发一版似乎也解决不了问题，因为之前的 `Keychain` 数据就是读取不到了，总不能再把 App 转让回去吧，😂

那么如何未雨绸缪预防以后再发生这种因为转让 App 导致存储在 `Keychain` 中的登录态丢失读取不到呢？（虽然出现转让 App 的概率非常低）

我们在新版本中采用了一种兼容的方法：把用户的登录态同时加密存储在本地缓存（`Sandbox`）和 `Keychain` 中，在 App 启动时，优先从 `Keychain` 中读取，如果 `Keychain` 中取不到，就从本地缓存中取（然后再把本地缓存的同步到 `Keychain` 中，因为即使 App 转让了，用户更新版本覆盖安装后 `Sandbox` 中的数据是不会变的），如果两处都取不到，就认为未登录。

你有没有更好的解决方案？欢迎留言讨论。

另外，有很多人通过 `Keychain` 来存储设备唯一标示符，也需要注意这个问题。

关于 `Keychain` 如何使用，可以参考苹果官方文档：[GenericKeychain](https://developer.apple.com/library/archive/samplecode/GenericKeychain/Introduction/Intro.html)，而关于 Keychain 滥用问题的讨论，可以看 V2EX 的[这个帖子](https://www.v2ex.com/t/471254)。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://awesome-tips.gitbook.io/ios/an-quan-yue-yu/content-3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
