您可以將驗證提供者憑證連結至現有的使用者帳戶,讓使用者透過多個驗證服務提供者登入您的應用程式。無論用來登入的驗證服務供應商為何,系統都會透過相同的 Firebase 使用者 ID 來識別使用者。舉例來說,使用密碼登入的使用者可以連結 Google 帳戶,日後再利用任一方法登入。或者,匿名使用者也可以連結 Facebook 帳戶,之後登入 Facebook 繼續使用您的應用程式。
事前準備
在應用程式中新增支援兩個以上驗證供應商 (可能包括匿名驗證) 的支援。
將驗證服務供應商憑證連結至使用者帳戶
如要將驗證提供者憑證與現有使用者帳戶建立連結,請按照下列步驟操作:
- 使用任何驗證提供者或方式登入使用者。
- 完成新驗證供應商的登入流程,但不包括呼叫其中一種
FIRAuth.signInWith
方法。例如,請取得使用者的 Google ID 權杖、Facebook 存取權杖或電子郵件地址和密碼。 取得新驗證供應商的
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];
將
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) { // ... }];