Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从iOS自动填充密码中保存/检索密码?_Ios_Swift_Nsuserdefaults_Keychain_Autofill - Fatal编程技术网

如何从iOS自动填充密码中保存/检索密码?

如何从iOS自动填充密码中保存/检索密码?,ios,swift,nsuserdefaults,keychain,autofill,Ios,Swift,Nsuserdefaults,Keychain,Autofill,我正在尝试实现苹果的自动填充密码。我终于让它工作了,但如果确实创建了凭据,我希望我的应用程序在应用程序启动时记住用户名/密码。我目前正在使用“KeychainSwift”pod存储用户名和密码,但我意识到Autofill无论如何都会创建一个新的密钥链(它们现在出现在我的iPhone保存的密码中),因此我不妨直接使用这些凭据。 我试着用这个来检索它,但是说“找不到匹配的项”: SecRequestSharedWebCredential(nil,nil){credentials,出现错误 guard

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

SecRequestSharedWebCredential(nil,nil){credentials,出现错误
guard let credentials=credentials else{print(“Keychain:找不到凭据”);return}
guard error==nil else{print(“Keychain error:,error?.localizedDescription??“无错误描述”);return}
让凭证:CFDictionary=unsafeBitCast(CFArrayGetValueAtIndex(凭证,i),到:CFDictionary.self)
让服务器=unsafeBitCast(CFDictionaryGetValue(凭证,unsafeBitCast(kSecAttrServer,to:UnsafeRawPointer.self)),to:CFString.self)
let account=unsafeBitCast(CFDictionaryGetValue(凭证,unsafeBitCast(kSecAttrAccount,to:UnsafeRawPointer.self)),to:CFString.self)
让password=unsafeBitCast(CFDictionaryGetValue(凭证,unsafeBitCast(kSecSharedPassword,to:UnsafeRawPointer.self)),to:CFString.self)
打印(“钥匙链确定:”,服务器,帐户,密码)
}
请求在第二个guard语句处停止执行,因为“error”不是nil。我错过什么了吗?这有可能吗

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

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

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


我被这些lol弄糊涂了。请,我需要帮助:)

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

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


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

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

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


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

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

以下是我对整个过程的了解:

只要启用自动填充(将contentType设置为
.username
.password
/
.newPassword
),并添加相关域,如果我使用自己的密码登录或注册,当活动ViewController被解除时,应用程序就会自动提示“保存密码”(有点酷,我不需要添加任何代码就可以将这些凭证添加到iCloud钥匙链中)。但是,如果我使用Apple的“强密码”注册,当我的活动ViewController被解除时(即,点击后退按钮,使用
InteractivePostureRecognitor
,甚至成功完成注册),它会自动将凭据添加到iCloud密钥链,甚至不会显示“保存密码?”提示(用户不知道也不同意)。我觉得这不应该发生,所以我刚刚提交了一个bug

现在,当凭据自动添加时,我们无法使用预期的函数来检索密码
SecRequestSharedWebCredential(nil,nil)
:将找不到任何凭据。只有使用
SecAddSharedWebCredential()手动添加密码时,我们才能检索密码。
(我也发现这有点像奇怪的行为,因为最终结果完全相同。)但这不是我想要的,因为
SecAddSharedWebCredential()
的提示符不同而且太冗长,
SecRequestSharedWebCredential()
也会显示一个提示符,即使我想以静默方式检索它(例如,将用户名存储在UserD中
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)
    }