在 Firebase iOS 中重用凭据以通过 Apple 登录

kAi*_*AiN 5 ios firebase swift firebase-authentication sign-in-with-apple

在阅读Firebase 文档如何使用相同的电子邮件但不同的凭据管理帐户错误后,我按照 Firebase 文档的建议修改了我的代码,但我仍然发现问题

当使用 Facebook 的身份验证遇到AuthErrorCode.accountExistsWithDifferentCredential.rawValue错误时,它会获取一个临时凭证(它可能发生在(error! As NSError) .userInfo [AuthErrorUserInfoUpdatedCredentialKey]

然后在 Firebase 中搜索用户迄今为止使用的提供程序 Auth.auth().fetchSignInMethods

当它遇到(在我的示例中)提供者"apple.com" 时,文档说要对用户进行身份验证并使用获得的临时凭证建立(如果一切顺利)与提供者的链接。

现在我的问题是,当Auth.auth().fetchSignInMethods遇到提供者“apple.com”时,我无法通过该提供者进行身份验证,因为苹果凭据只能使用一次......所以此时我想知道我是如何摆脱的这种情况?

如果我们按照文档说明使用EmailAuthProviderID进行身份验证,但显然我认为这只是一个示例 .. 在文档中,我认为与(在我的情况下)提供者“apple.com”遇到了EmailAuthProviderID而不是会面......


我对文档的这种解释有误吗?

我是否犯了其他错误而没有意识到?

Facebook 帐户可以不链接到现有的 Apple 帐户吗?


抱歉,我已经在这个问题上纠结了好几天了..

这是更新后的代码

Auth.auth().signIn(with: FacebookAuthProvider.credential(withAccessToken: authToken)) { authResult, error in
    if error != nil {
      // Handle error.
        if (error as NSError?)?.code == AuthErrorCode.accountExistsWithDifferentCredential.rawValue {
            // Get pending credential and email of existing account.
            let existingAcctEmail = (error! as NSError).userInfo[AuthErrorUserInfoEmailKey] as! String
            let pendingCred = (error! as NSError).userInfo[AuthErrorUserInfoUpdatedCredentialKey] as! AuthCredential

            Auth.auth().fetchSignInMethods(forEmail: existingAcctEmail) { (methods, error) in

                if (methods?.contains("apple.com"))! {

                    // **** This Flow stops here because I can't reuse Apple's credentials a second time. *****

                    let tokenID = KeychainManager.getItemFromKeychain(forKey: AuthKey.applTokenID, keyPrefix: AuthKey.prefix)!
                    let nonce = KeychainManager.getItemFromKeychain(forKey: AuthKey.applNonce, keyPrefix: AuthKey.prefix)

                    let appleCredentials = OAuthProvider.credential(withProviderID: "apple.com", accessToken: tokenID)


                    Auth.auth().signIn(with: appleCredentials) { user, error in
                        if user != nil {
                          // Link pending credential to account.
                          Auth.auth().currentUser?.link(with: pendingCred) { result, error in
                            // ...
                            print("\n LINK")

                            }
                        }
                        else {
                            print(error!)

                        }
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

kAi*_*AiN 3

这是我采用的解决方案..显然它必须根据您的应用程序的功能进行定制


到目前为止,我已经解决了要求用户使用现有提供商登录的问题。当用户使用现有提供商登录时,他会创建与所选提供商的连接。

我解释 ...

如果用户想要使用Apple登录并且已经存在 Google帐户,则应以这种方式设置代码,以确保用户确实想要连接两个提供商:

  1. 在AutenticationService 的委托方法中didCompleteWithAuthorization authorization: (如果用户是第一次用apple登录)用Auth.auth()进行检查。FetchSignInMethods哪些提供商已经存在,并从他的 appleID 信息中检索到他的电子邮件

笔记

Apple 的用户数据仅在首次访问时提供。对于通过 Apple 登录进行的所有其他访问,将不会提供用户数据


  1. 如果没有与用户电子邮件关联的提供商,请完成身份验证流程

    2.1 . 如果现有提供商具有相同的电子邮件(例如GOOGLE),首先我们会显示一条通知,告知用户哪些提供商与其电子邮件关联(之前与其他提供商进行了身份验证),然后我们允许用户选择与哪个提供商合作(本例中为GOOGLE)想要登录以连接Apple

    2.2当用户选择连接Apple 的提供商 ( GOOGLE ) 时,我们会调用现有提供商的身份验证流程(就好像用户按下GOOGLE按钮一样)。

此时包含身份验证流程(在我们的例子中为Google),如果一切成功,我们将Auth.auth (). CurrentUser.link (with: credential)使用 Apple 凭据进行调用


笔记:

在这一切中,当用户按下按钮时,Apple 的凭据保存在钥匙串内,并在与现有提供商链接后立即删除

Apple 凭证一旦使用就无法重复使用