קישור של מספר ספקי אימות לחשבון בפלטפורמות של Apple

אתם יכולים לאפשר למשתמשים להיכנס לאפליקציה שלכם באמצעות כמה ספקי אימות על ידי קישור פרטי הכניסה של ספק האימות לחשבון משתמש קיים. אפשר לזהות משתמשים באמצעות אותו מזהה משתמש ב-Firebase, בלי קשר לספק האימות שבו הם השתמשו כדי להיכנס לחשבון. לדוגמה, משתמש שנכנס באמצעות סיסמה יכול לקשר חשבון Google ולהיכנס באמצעות אחת מהשיטות האלה בעתיד. לחלופין, משתמש אנונימי יכול לקשר חשבון פייסבוק, ואז להיכנס לחשבון באמצעות פייסבוק כדי להמשיך להשתמש באפליקציה.

לפני שמתחילים

מוסיפים לאפליקציה תמיכה בשני ספקי אימות או יותר (יכול להיות שזה כולל אימות אנונימי).

כדי לקשר פרטי כניסה של ספק אימות לחשבון משתמש קיים:

  1. מבצעים כניסה לחשבון המשתמש באמצעות ספק או שיטת אימות כלשהם.
  2. משלימים את תהליך הכניסה של ספק האימות החדש עד לשלב של קריאה לאחת מהשיטות של FIRAuth.signInWith, אבל לא כולל השלב הזה. לדוגמה, קבלת טוקן מזהה של משתמש ב-Google, טוקן גישה בפייסבוק או כתובת אימייל וסיסמה.
  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.

אפשר לבטל את הקישור של ספק אימות לחשבון, כך שהמשתמש לא יוכל יותר להיכנס לחשבון באמצעות הספק הזה.

כדי לבטל את הקישור של ספק אימות לחשבון משתמש, מעבירים את מזהה הספק לשיטה unlink. אפשר לקבל את מזהי הספקים של ספקי האימות שמקושרים למשתמש מתוך providerDataהנכס.

Swift

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

Objective-C

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

פתרון בעיות

אם נתקלתם בשגיאות כשניסיתם לקשר כמה חשבונות, תוכלו לעיין במסמכים בנושא כתובות אימייל מאומתות.