چندین ارائه دهنده تأیید اعتبار را به یک حساب در پلتفرم های اپل پیوند دهید

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

قبل از اینکه شروع کنی

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

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

  1. کاربر را با استفاده از هر ارائه دهنده یا روش احراز هویتی وارد سیستم کنید.
  2. روند ورود به سیستم برای ارائه‌دهنده‌ی احراز هویت جدید را تا فراخوانی یکی از متدهای FIRAuth.signInWith تکمیل کنید، اما این کار را شامل نمی‌شود. برای مثال، توکن شناسه‌ی گوگل کاربر، توکن دسترسی فیسبوک یا ایمیل و رمز عبور را دریافت کنید.
  3. یک FIRAuthCredential برای ارائه‌دهنده‌ی احراز هویت جدید دریافت کنید:

    ورود به سیستم گوگل
    سویفت
    guard
      let authentication = user?.authentication,
      let idToken = authentication.idToken
    else {
      return
    }
    
    let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                   accessToken: authentication.accessToken)
    هدف-سی
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:result.user.idToken.tokenString
                                     accessToken:result.user.accessToken.tokenString];
    ورود به فیسبوک
    سویفت
    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: کاربر وارد شده ارسال کنید:

    سویفت
        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 دسترسی پیدا کند.

یک حساب کاربری Firebase می‌تواند چندین ارائه‌دهنده‌ی احراز هویت (مثلاً ایمیل/رمز عبور، گوگل، فیس‌بوک) داشته باشد که به کاربر اجازه می‌دهد از طریق روش‌های مختلف به یک حساب Firebase وارد شود.

اگر ارتباط یک ارائه‌دهنده‌ی احراز هویت را با حساب کاربری قطع کنید، کاربر دیگر نمی‌تواند با آن ارائه‌دهنده وارد سیستم شود.

برای قطع ارتباط یک ارائه‌دهنده‌ی احراز هویت از یک حساب کاربری، شناسه‌ی ارائه‌دهنده را به متد unlink ارسال کنید. می‌توانید شناسه‌های ارائه‌دهنده‌ی ارائه‌دهندگان احراز هویت مرتبط با یک کاربر را از ویژگی providerData دریافت کنید.

سویفت

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

هدف-سی

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

عیب‌یابی

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