Połącz wielu dostawców uwierzytelniania z kontem na platformach Apple

Możesz zezwolić użytkownikom na logowanie się do Twojej aplikacji przy użyciu wielu dostawców uwierzytelniania, łącząc poświadczenia dostawcy uwierzytelniania z istniejącym kontem użytkownika. Użytkowników można zidentyfikować za pomocą tego samego identyfikatora użytkownika Firebase, niezależnie od dostawcy uwierzytelniania, którego użyli do zalogowania. Na przykład użytkownik, który zalogował się przy użyciu hasła, może w przyszłości połączyć konto Google i zalogować się dowolną metodą. Lub anonimowy użytkownik może połączyć konto na Facebooku, a następnie zalogować się za pomocą Facebooka, aby dalej korzystać z aplikacji.

Zanim zaczniesz

Dodaj obsługę co najmniej dwóch dostawców uwierzytelniania (możliwe, że w tym uwierzytelnianie anonimowe) do swojej aplikacji.

Aby połączyć poświadczenia dostawcy uwierzytelniania z istniejącym kontem użytkownika:

  1. Zaloguj się użytkownika przy użyciu dowolnego dostawcy lub metody uwierzytelniania.
  2. Zakończ proces logowania dla nowego dostawcy uwierzytelniania, aż do wywołania jednej z metod FIRAuth.signInWith , ale nie w tym. Na przykład uzyskaj token identyfikatora Google użytkownika, token dostępu do Facebooka lub adres e-mail i hasło.
  3. Uzyskaj FIRAuthCredential dla nowego dostawcy uwierzytelniania:

    Logowanie przez Google
    Szybki
    guard
      let authentication = user?.authentication,
      let idToken = authentication.idToken
    else {
      return
    }
    
    let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                   accessToken: authentication.accessToken)
    
    Cel C
    GIDAuthentication *authentication = user.authentication;
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken
                                     accessToken:authentication.accessToken];
    
    Nazwa użytkownika Facebook
    Szybki
    let credential = FacebookAuthProvider
      .credential(withAccessToken: AccessToken.current!.tokenString)
    
    Cel C
    FIRAuthCredential *credential = [FIRFacebookAuthProvider
        credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    
    E-mail-hasło logowania
    Szybki
    let credential = EmailAuthProvider.credential(withEmail: email, password: password)
    
    Cel C
    FIRAuthCredential *credential =
        [FIREmailAuthProvider credentialWithEmail:email
                                                 password:password];
    
  4. Przekaż obiekt FIRAuthCredential do metody linkWithCredential:completion: zalogowanego użytkownika:

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

    Wywołanie linkWithCredential:completion: zakończy się niepowodzeniem, jeśli poświadczenia są już połączone z innym kontem użytkownika. W takiej sytuacji musisz obsłużyć scalanie kont i powiązanych danych odpowiednio do Twojej aplikacji:

    Szybki

    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
                // ...
            }
    

    Cel 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
                                        // ...
                                    }];
    

Jeśli wywołanie linkWithCredential:completion: powiedzie się, użytkownik może teraz zalogować się przy użyciu dowolnego połączonego dostawcy uwierzytelniania i uzyskać dostęp do tych samych danych Firebase.

Możesz odłączyć dostawcę uwierzytelniania od konta, aby użytkownik nie mógł już logować się u tego dostawcy.

Aby odłączyć dostawcę uwierzytelniania od konta użytkownika, przekaż identyfikator dostawcy do metody unlinkFromProvider:completion: Identyfikatory dostawców dostawców uwierzytelniania połączonych z użytkownikiem można uzyskać z właściwości providerData .

Szybki

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

Cel C

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