קישור ספקי אימות מרובים לחשבון ב- iOS

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

לפני שאתה מתחיל

הוסף תמיכה עבור שני ספקי אימות או יותר (אולי כולל אימות אנונימי) לאפליקציה שלך.

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

  1. היכנס למשתמש באמצעות כל ספק או שיטת אימות.
  2. השלם את זרימת הכניסה לספק האימות החדש עד FIRAuth.signInWith משיטות FIRAuth.signInWith , אך לא כולל. לדוגמה, קבל את אסימון מזהה Google של המשתמש, אסימון גישה לפייסבוק או דוא"ל וסיסמה.
  3. קבל FIRAuthCredential לספק האימות החדש:

    כניסה ל- Google
    מָהִיר
    guard let authentication = user.authentication else { return }
    let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                   accessToken: authentication.accessToken)
    
    מטרה-ג
    GIDAuthentication *authentication = user.authentication;
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken
                                     accessToken:authentication.accessToken];
    
    כניסה לפייסבוק
    מָהִיר
    let credential = FacebookAuthProvider
      .credential(withAccessToken: AccessToken.current!.tokenString)
    
    מטרה-ג
    FIRAuthCredential *credential = [FIRFacebookAuthProvider
        credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    
    כניסה לסיסמה בדוא"ל
    מָהִיר
    let credential = EmailAuthProvider.credential(withEmail: email, password: password)
    
    מטרה-ג
    FIRAuthCredential *credential =
        [FIREmailAuthProvider credentialWithEmail:email
                                                 password:password];
    
  4. העבר את האובייקט FIRAuthCredential המשתמש linkWithCredential:completion: method:

    מָהִיר
        user.link(with: credential) { authResult, error in
      // ...
    }
    }
    
    מטרה-ג
        [[FIRAuth auth].currentUser linkWithCredential:credential
        completion:^(FIRAuthDataResult *result, NSError *_Nullable error) {
      // ...
    }];
    

    הקריאה ל- linkWithCredential:completion: תיכשל אם האישורים כבר מקושרים לחשבון משתמש אחר. במצב זה, עליכם לטפל במיזוג החשבונות והנתונים המשויכים בהתאם לאפליקציה שלכם:

    מָהִיר

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

    מטרה-ג

    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.

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

כדי לבטל קישור של ספק אימות מחשבון משתמש, העבירו את מזהה הספק ל- unlinkFromProvider:completion: method. אתה יכול לקבל את מזהי הספקים של ספקי האימות המקושרים למשתמש ממאפיין providerData .

מָהִיר

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

מטרה-ג

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