پیوند دادن چند ارائه‌دهنده اصالت‌سنجی به یک حساب در پلاتفرم‌های Apple

می‌توانید به کاربران اجازه دهید با پیوند دادن اطلاعات اعتباری ارائه‌دهنده اصالت‌سنجی به حساب کاربری موجود، بااستفاده از چندین ارائه‌دهنده اصالت‌سنجی به سیستم برنامه‌تان وارد شوند. کاربران صرف‌نظر از ارائه‌دهنده اصالت‌سنجی که برای ورود به سیستم استفاده کرده‌اند، با همان شناسه کاربر Firebase قابل‌شناسایی هستند. برای مثال، کاربری که با گذرواژه به سیستم وارد شده است می‌تواند «حساب Google» را پیوند دهد و در آینده با هریک از این روش‌ها به سیستم وارد شود. یا، کاربر ناشناسی می‌تواند حساب Facebook را پیوند دهد و سپس، بعداً با Facebook به سیستم وارد شود تا به استفاده از برنامه شما ادامه دهد.

قبل از شروع

پشتیبانی از دو یا چند ارائه‌دهنده اصالت‌سنجی (احتمالاً شامل اصالت‌سنجی ناشناس) را به برنامه‌تان اضافه کنید.

برای پیوند دادن اطلاعات اعتباری ارائه‌دهنده اصالت‌سنجی به حساب کاربری موجود:

  1. کاربر را بااستفاده از هر روش یا ارائه‌دهنده اصالت‌سنجی به سیستم وارد کنید.
  2. جریان ورود به سیستم را برای ارائه‌دهنده اصالت‌سنجی جدید تا مرحله فراخوانی یکی از روش‌های FIRAuth.signInWith تکمیل کنید، اما این مرحله را شامل نشود. برای مثال، گذرکلید Google کاربر، گذرکلید دسترسی 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];
    ورود به سیستم فیس‌بوک
    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 دسترسی پیدا کند.

یک حساب کاربری Firebase می‌تواند چندین ارائه‌دهنده اصالت‌سنجی پیوندشده داشته باشد (برای مثال، ایمیل/گذرواژه، Google،‏ Facebook)، که به کاربر امکان می‌دهد ازطریق روش‌های مختلف به همان حساب 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) {
  // ...
}];

عیب‌یابی

اگر هنگام تلاش برای پیوند دادن چند حساب با خطا مواجه شدید، مستندات مربوط به نشانی‌های ایمیل تأییدشده را ببینید.