首页 > 解决方案 > Apple 登录导致 FIRAuthErrorUserInfoNameKey=ERROR_EMAIL_ALREADY_IN_USE(代码 = 17007)

问题描述

使用 SwiftUI、Xcode12.5.1、Swift5.4.2、iOS14.7.1、

我的 Firebase 电子邮件/密码登录页面应扩展为其他登录可能性,例如 Apple 登录(最终是谷歌登录、Facebook 登录等)。

我的步骤:

  1. 使用电子邮件/密码登录 Firebase
  2. 登出
  3. 使用“Sign in with Apple”登录->然后我收到以下错误:
Error Domain=FIRAuthErrorDomain Code=17007

"The email address is already in use by another account."

UserInfo={NSLocalizedDescription=The email address is already in use by another account.,

FIRAuthErrorUserInfoNameKey=ERROR_EMAIL_ALREADY_IN_USE}

我打算做的是将现有Email/Password-Firebase的 -Account 链接到Sign in with Apple-Account (如herehere所述)。

但为此,我需要FIRAuthErrorUserInfoUpdatedCredentialKey允许最终检索旧用户的错误。

就我而言,我得到 ERROR_EMAIL_ALREADY_IN_USE 不会导致任何旧用户被链接。

我需要做什么 ?

这是我的代码:

let credential = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)

Auth.auth().signIn(with: credential) { (authResult, error) in

    if (error != nil) {
        print(error?.localizedDescription as Any)
        return
    }
    print("signed in with Apple...")
    
    do {
        // if user did log in with Email/Password previously
        if let email = try THKeychain.getEmail(),
           let password = try THKeychain.getPassword() {

            let credential = EmailAuthProvider.credential(withEmail: email, password: password)

            if let user = authResult?.user {

                // here I am trying to link the existing Firebase-Email/Password account to the just signed-in with Apple account
                user.link(with: credential) { (result, linkError) in
                    
                    print(linkError)  // this is where I get FIRAuthErrorUserInfoNameKey=ERROR_EMAIL_ALREADY_IN_USE
                    
                    // unfortunately, the two accounts are not linked as expected due to this error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                    // What is missing ??????????????????
                    
                    loginStatus = true
                }
            }
        } else {
            loginStatus = true
        }
    } catch {
        print(error.localizedDescription)
    }
}

在 Firebase 文档中,它说:

Sign in with Apple will not allow you to reuse an auth credential to link to an existing account. If you want to link a Sign in with Apple credential to another account, you must first attempt to link the accounts using the old Sign in with Apple credential and then examine the error returned to find a new credential. The new credential will be located in the error's userInfo dictionary and can be accessed via the FIRAuthErrorUserInfoUpdatedCredentialKey key.

“...如果您想将 Sign in with Apple 凭据链接到另一个帐户,您必须首先尝试使用旧的 Sign in with Apple 凭据...”部分是什么意思?什么是old Sign in with Apple credential??????

我该怎么做?

事实上,在链接调用中,我实际上期望某种linkError.userInfo更新的用户可以登录。但是我的示例中的 linkError 只给了我ERROR_EMAIL_ALREADY_IN_USE错误,而没有进一步的 userInfo。

正如Peter Friese 在他的博客中提到的那样,我应该能够以某种方式AuthErrorUserInfoUpdatedCredentialKey从 error.userInfo 中检索 a。但就我而言,linkError 没有任何此类信息 - 不幸的是!

这是彼得示例的摘录:(由于某些未知原因,再次不适用于我的情况??????)

currentUser.link(with: credential) { (result, error) in // (1)
    if let error = error, (error as NSError).code == AuthErrorCode.credentialAlreadyInUse.rawValue { // (2)
        print("The user you're signing in with has already been linked, signing in to the new user and migrating the anonymous users [\(currentUser.uid)] tasks.")
        if let updatedCredential = (error as NSError).userInfo[AuthErrorUserInfoUpdatedCredentialKey] as? OAuthCredential {
            print("Signing in using the updated credentials")
            Auth.auth().signIn(with: updatedCredential) { (result, error) in
                if let user = result?.user {
                    // TODO: handle data migration
                    self.doSignIn(appleIDCredential: appleIDCredential, user: user) // (3)
                }
            }
        }
    }
}

标签: firebasegoogle-cloud-firestorefirebase-authenticationgoogle-signinsign-in-with-apple

解决方案


颠倒链接的顺序让我进步了一点。

如果我按下Sign in with Apple按钮,我的代码现在首先使用 Firebase-Email/Password 登录(即从钥匙串中获取必要的凭据)。第二步,与 Apple 凭证的链接。通过这样做,链接最终AuthErrorUserInfoUpdatedCredentialKey在链接回调中给了我想要的。

在那里我检索updatedCredential到使用 Apple 登录。

请参阅下面的代码。

但是,我仍然不知道为什么以这种方式登录后,我的数据仍然丢失??????

这个数据迁移步骤是如何工作的???

不应该user.link(with: appleCredentials) { ... }做这项工作吗?

无论登录方法如何,我都需要做什么才能获得相同的 Firebase-Data ???

let appleCredentials = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)

do {
    // if user did log in with Email/Password anytime before
    if let email = try THKeychain.getEmail(),
       let password = try THKeychain.getPassword() {
        
        let firebaseEmailCredentials = EmailAuthProvider.credential(withEmail: email, password: password)
        
        Auth.auth().signIn(with: firebaseEmailCredentials) { (authResult, error) in
            
            if let user = authResult?.user {
                
                user.link(with: appleCredentials) { (result, linkError) in
                    
                    if let linkError = linkError, (linkError as NSError).code == AuthErrorCode.credentialAlreadyInUse.rawValue {
                        
                        print("The user you're signing in with has been linked.")
                        print("Signing in to Apple and migrating the email/pw-firebase-users [\(user.uid)]` data.")
                        if let updatedCredential = (linkError as NSError).userInfo[AuthErrorUserInfoUpdatedCredentialKey] as? OAuthCredential {
                            
                            print("Signing in using the updated credentials")
                            Auth.auth().signIn(with: updatedCredential) { (result, error) in
                                if let _ = result?.user {
                                    print("signed in with Apple...")
                                    // TODO: handle data migration
                                    print("Data-migration takes place now...")
                                    
                                    loginStatus = true
                                }
                            }
                        }
                    }
                    else if let error = error {
                        print("Error trying to link user: \(error.localizedDescription)")
                    }
                    else {
                        if let _ = result?.user {
                            loginStatus = true
                        }
                    }
                }
            }
        }
    } else {
        // case where user never logged in with firebase-Email/Password before
        Auth.auth().signIn(with: appleCredentials) { (result, error) in
            if let _ = result?.user {
                print("signed in with Apple...")
                loginStatus = true
            }
        }
    }
} catch {
    print(error.localizedDescription)
}

推荐阅读