【问题标题】:How to save/retrieve password from iOS Autofill Password?如何从 iOS 自动填充密码中保存/检索密码?
【发布时间】:2019-09-15 10:04:00
【问题描述】:

我正在尝试实施 Apple 的自动填充密码。我终于让它工作了,但如果确实创建了凭据,我希望我的应用程序记住应用程序启动时的用户名/密码。我目前正在使用“KeychainSwift”窗格存储用户名和密码,但我意识到自动填充无论如何都会创建一个新的钥匙串(它们现在出现在我的 iPhone 保存的密码中),所以我不妨直接使用这些凭据。 我试着用这个来检索它,但说“没有找到匹配的项目”:

SecRequestSharedWebCredential(nil, nil){ credentials, error in
        guard let credentials = credentials else { print("Keychain: No credentials found"); return }
        guard error == nil else { print("Keychain Error:", error?.localizedDescription ?? "no error description"); return }

        let credential: CFDictionary = unsafeBitCast(CFArrayGetValueAtIndex(credentials, i), to: CFDictionary.self)
        let server = unsafeBitCast(CFDictionaryGetValue(credential, unsafeBitCast(kSecAttrServer, to: UnsafeRawPointer<Void>.self)), to: CFString.self)
        let account = unsafeBitCast(CFDictionaryGetValue(credential, unsafeBitCast(kSecAttrAccount, to: UnsafeRawPointer<Void>.self)), to: CFString.self)
        let password = unsafeBitCast(CFDictionaryGetValue(credential, unsafeBitCast(kSecSharedPassword, to: UnsafeRawPointer<Void>.self)), to: CFString.self)

        print("Keychain OK:", server, account, password)
    }

请求在第二个保护语句处停止执行,因为 'error' 不是 nil。我错过了什么吗?这有可能吗?

编辑#1: 我一直在阅读所有这些内容,并且感觉每当用户注册或登录时,我都必须单独保存/加载用户名/密码组合(通过 Keychain 或 UserDefaults)。谁能确认这是预期的行为?对我来说似乎很奇怪,因为自动填充已经将这些凭据存储在某个地方(我假设是钥匙串),因为 FaceID 会弹出并使用我在注册期间提供的正确用户名/密码自动填充文本字段。

编辑#2这是我最理想的目标:键盘的 QuickType 上的自动填充选项,当用户注册/登录以将其添加到设置 > 密码和帐户 > 中显示的已保存密码中时网站和应用程序密码”。也许我无法理解自动填充的实际流程,或者 iCloud 钥匙串和共享网络凭据之间的区别,但我无法理解如何实现我所需要的。

相反,发生了很多意想不到的事情(错误?):点击自动填充会自动创建新凭据,但我无法使用上面发布的代码检索它们,但如果我手动添加它SecAddSharedWebCredential() 然后我可以检索它们。为什么?它们实际上都出现在我保存的密码中,在同一个域下,具有相同的应用程序图标。此外,当 Signin ViewController 被解除(执行 Segue)时,我会收到保存密码的提示,但是当我尝试使用用户名 + 强烈建议的密码进行注册然后按下 Back(这会解除 ViewController)时,它仍然会将其添加到保存密码,这次甚至没有提示我保存密码!

我被这一切弄糊涂了,哈哈。拜托,我需要帮助:)

【问题讨论】:

  • 我理解的方式是我们永远无法直接访问密码 - 这就是 Apple 实现它的方式的重点。用户可以(如果他们愿意)在文本字段等中输入密码,但我认为它们不会存储在我们可以直接访问它们的任何地方。想想开发人员仅仅能够从钥匙串中获取密码的安全隐患!
  • 将用户密码保存在prefs中,使用for username作为key,当用户输入用户名并在textField中设置时访问它。
  • @ Abu,所以你建议自己存储密码,明白了。 @ siburg,我们可以直接访问密码。使用共享 Web 凭据,如果我使用 SecAddSharedWebCredential() 设置凭据,然后我可以通过调用 SecRequestSharedWebCredential() 访问密码。我只是困惑为什么我必须显式调用 SecAddSharedWebCredential() 如果它在 ViewController 被解除时自动创建凭据。

标签: ios swift nsuserdefaults keychain autofill


【解决方案1】:

快速回答:您可以使用自动填充功能保存/检索密码只有在您手动添加密码时使用SecAddSharedWebCredential()

这是我对整个过程的了解:

只需启用自动填充(将 contentType 设置为.username.password/.newPassword,以及添加关联域),应用程序就会自动提示“保存密码?”如果我使用自己的密码登录或注册,活动的 ViewController 会被关闭(有点酷,我不需要添加任何代码即可将这些凭据添加到 iCloud 钥匙串)。但是,如果我使用 Apple 的“强密码”注册,当我的活动 ViewController 被关闭(即通过点击返回按钮、使用 interactivePopGestureRecognizer,甚至成功完成注册)时,它会自动添加iCloud钥匙串的凭据甚至没有显示“保存密码?”提示(用户不知情或不同意)。我觉得这不应该发生,所以我刚刚提交了一个错误。

现在,当自动添加凭据时,我们无法使用预期功能SecRequestSharedWebCredential(nil,nil) 检索密码:找不到凭据。 如果我们手动添加了SecAddSharedWebCredential(),我们只能检索密码(我也觉得这有点像奇怪的行为,因为最终结果完全相同)。但这不是我想要的,因为SecAddSharedWebCredential() 的提示不同且过于冗长,而SecRequestSharedWebCredential() 也会显示提示,即使我想静默检索它(例如,通过将用户名存储在 UserDefaults 中并使用SecRequestSharedWebCredential(nil, username).

结论:我无法做我想做的事(使用 iCloud 钥匙串来保存和静默检索正确的凭据,而无需在我自己的应用钥匙串中复制)。我最终在我的应用程序钥匙串上单独存储用户名/哈希以进行自动登录,并且我保持启用自动填充以快速登录,以防用户需要临时注销(从我的应用程序钥匙串中删除用户名/哈希)同时保存了iCloud 钥匙串中的密码。

【讨论】:

    【解决方案2】:

    您不应存储用户名和密码。当用户第一次登录时,您应该生成令牌。令牌应存储在您的应用钥匙串中。当用户第二次启动您的应用程序时,您应该使用令牌登录。

    存储令牌比存储用户名和密码安全得多。

    如果你想存储密码,那么至少只存储密码哈希而不是纯文本。

    【讨论】:

    • 即使存储密码哈希也不是最好的。如果有什么哈希和盐它。
    • 我提到“密码”是为了让论证更简单,因为问题已经相当复杂了。我正在寻找有关如何处理自动填充及其使用的凭据(保存和检索它们)的建议。
    猜你喜欢
    • 2018-09-04
    • 2019-11-01
    • 2019-03-10
    • 2019-09-02
    • 2020-01-23
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多