將多個驗證供應商連結至 Apple 平台的帳戶

您可以將驗證供應商憑證連結至現有使用者帳戶,允許使用者透過多個驗證供應商登入應用程式。無論使用者透過哪個驗證提供者登入,系統都會使用相同的 Firebase 使用者 ID 識別使用者。舉例來說,以密碼登入的使用者可以連結 Google 帳戶,日後就能透過任一方法登入。或者,匿名使用者可以連結 Facebook 帳戶,然後稍後使用 Facebook 登入,繼續使用您的應用程式。

事前準備

在應用程式中新增對兩個以上驗證供應商的支援 (可能包括匿名驗證)。

如要將驗證供應商憑證連結至現有使用者帳戶,請按照下列步驟操作:

  1. 使用任何驗證供應商或方法登入使用者。
  2. 完成新驗證供應商的登入流程,但不要呼叫 FIRAuth.signInWith 方法。例如,取得使用者的 Google ID 權杖、Facebook 存取權杖,或是電子郵件和密碼。
  3. 取得新驗證供應商的 FIRAuthCredential

    Google 登入
    Swift
    guard   let authentication = user?.authentication,   let idToken = authentication.idToken else {   return }  let credential = GoogleAuthProvider.credential(withIDToken: idToken,                                                accessToken: authentication.accessToken)
    Objective-C
    FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:result.user.idToken.tokenString                                  accessToken:result.user.accessToken.tokenString];
    Facebook 登入
    Swift
    let credential = FacebookAuthProvider   .credential(withAccessToken: AccessToken.current!.tokenString)
    Objective-C
    FIRAuthCredential *credential = [FIRFacebookAuthProvider     credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    使用電子郵件地址和密碼登入
    Swift
    let credential = EmailAuthProvider.credential(withEmail: email, password: password)
    Objective-C
    FIRAuthCredential *credential =     [FIREmailAuthProvider credentialWithEmail:email                                              password:password];
  4. FIRAuthCredential 物件傳遞至已登入使用者的 linkWithCredential:completion: 方法:

    Swift
        user.link(with: credential) { authResult, error in   // ... } }
    Objective-C
        [[FIRAuth auth].currentUser linkWithCredential:credential     completion:^(FIRAuthDataResult *result, NSError *_Nullable error) {   // ... }];

    如果憑證已連結至其他使用者帳戶,對 linkWithCredential:completion: 的呼叫就會失敗。在這種情況下,您必須視應用程式需求,處理帳戶和相關聯資料的合併作業:

    Swift

    let prevUser = Auth.auth().currentUser Auth.auth().signIn(with: credential) { authResult, error in     if let error = error {       let authError = error as NSError       if isMFAEnabled, authError.code == AuthErrorCode.secondFactorRequired.rawValue {         // The user is a multi-factor user. Second factor challenge is required.         let resolver = authError           .userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver         var displayNameString = ""         for tmpFactorInfo in resolver.hints {           displayNameString += tmpFactorInfo.displayName ?? ""           displayNameString += " "         }         self.showTextInputPrompt(           withMessage: "Select factor to sign in\n\(displayNameString)",           completionBlock: { userPressedOK, displayName in             var selectedHint: PhoneMultiFactorInfo?             for tmpFactorInfo in resolver.hints {               if displayName == tmpFactorInfo.displayName {                 selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo               }             }             PhoneAuthProvider.provider()               .verifyPhoneNumber(with: selectedHint!, uiDelegate: nil,                                  multiFactorSession: resolver                                    .session) { verificationID, error in                 if error != nil {                   print(                     "Multi factor start sign in failed. Error: \(error.debugDescription)"                   )                 } else {                   self.showTextInputPrompt(                     withMessage: "Verification code for \(selectedHint?.displayName ?? "")",                     completionBlock: { userPressedOK, verificationCode in                       let credential: PhoneAuthCredential? = PhoneAuthProvider.provider()                         .credential(withVerificationID: verificationID!,                                     verificationCode: verificationCode!)                       let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator                         .assertion(with: credential!)                       resolver.resolveSignIn(with: assertion!) { authResult, error in                         if error != nil {                           print(                             "Multi factor finanlize sign in failed. Error: \(error.debugDescription)"                           )                         } else {                           self.navigationController?.popViewController(animated: true)                         }                       }                     }                   )                 }               }           }         )       } else {         self.showMessagePrompt(error.localizedDescription)         return       }       // ...       return     }     // User is signed in     // ... }             // Merge prevUser and currentUser accounts and data             // ...         }

    Objective-C

    FIRUser *prevUser = [FIRAuth auth].currentUser; [[FIRAuth auth] signInWithCredential:credential                           completion:^(FIRAuthDataResult * _Nullable authResult,                                        NSError * _Nullable error) {     if (isMFAEnabled && error && error.code == FIRAuthErrorCodeSecondFactorRequired) {       FIRMultiFactorResolver *resolver = error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];       NSMutableString *displayNameString = [NSMutableString string];       for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) {         [displayNameString appendString:tmpFactorInfo.displayName];         [displayNameString appendString:@" "];       }       [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Select factor to sign in\n%@", displayNameString]                            completionBlock:^(BOOL userPressedOK, NSString *_Nullable displayName) {        FIRPhoneMultiFactorInfo* selectedHint;        for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) {          if ([displayName isEqualToString:tmpFactorInfo.displayName]) {            selectedHint = (FIRPhoneMultiFactorInfo *)tmpFactorInfo;          }        }        [FIRPhoneAuthProvider.provider         verifyPhoneNumberWithMultiFactorInfo:selectedHint         UIDelegate:nil         multiFactorSession:resolver.session         completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {           if (error) {             [self showMessagePrompt:error.localizedDescription];           } else {             [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Verification code for %@", selectedHint.displayName]                                  completionBlock:^(BOOL userPressedOK, NSString *_Nullable verificationCode) {              FIRPhoneAuthCredential *credential =                  [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID                                                               verificationCode:verificationCode];              FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];              [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {                if (error) {                  [self showMessagePrompt:error.localizedDescription];                } else {                  NSLog(@"Multi factor finanlize sign in succeeded.");                }              }];            }];           }         }];      }];     }   else if (error) {     // ...     return;   }   // User successfully signed in. Get user data from the FIRUser object   if (authResult == nil) { return; }   FIRUser *user = authResult.user;   // ... }];                                     // Merge prevUser and currentUser accounts and data                                     // ...                                 }];

如果對 linkWithCredential:completion: 的呼叫成功,使用者現在就能使用任何已連結的驗證供應商登入,並存取相同的 Firebase 資料。

您可以取消驗證供應商與帳戶的連結,這樣使用者就無法再透過該供應商登入。

如要取消授權提供者與使用者帳戶的連結,請將提供者 ID 傳遞至 unlink 方法。您可以從 providerData 屬性取得連結至使用者的驗證供應商 ID。

Swift

Auth.auth().currentUser?.unlink(fromProvider: providerID!) { user, error in   // ... }

Objective-C

[[FIRAuth auth].currentUser unlinkFromProvider:providerID                                     completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {   // ... }];

疑難排解

如果嘗試連結多個帳戶時發生錯誤,請參閱已驗證電子郵件地址的說明文件。