เชื่อมโยงผู้ให้บริการรับรองความถูกต้องหลายรายเข้ากับบัญชีบนแพลตฟอร์ม Apple

คุณสามารถอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณโดยใช้ผู้ให้บริการตรวจสอบสิทธิ์หลายรายได้โดยการเชื่อมโยงข้อมูลประจำตัวของผู้ให้บริการตรวจสอบสิทธิ์กับบัญชีผู้ใช้ที่มีอยู่ ผู้ใช้สามารถระบุตัวผู้ใช้ได้ด้วย ID ผู้ใช้ Firebase เดียวกัน ไม่ว่าผู้ให้บริการตรวจสอบสิทธิ์ที่พวกเขาใช้ลงชื่อเข้าใช้จะเป็นคนใดก็ตาม ตัวอย่างเช่น ผู้ใช้ที่ลงชื่อเข้าใช้ด้วยรหัสผ่านสามารถเชื่อมโยงบัญชี Google และลงชื่อเข้าใช้ด้วยวิธีใดวิธีหนึ่งได้ในอนาคต หรือผู้ใช้ที่ไม่ระบุชื่อสามารถเชื่อมโยงบัญชี Facebook จากนั้นลงชื่อเข้าใช้ด้วย Facebook เพื่อใช้แอปของคุณต่อไปได้ในภายหลัง

ก่อนที่คุณจะเริ่ม

เพิ่มการรองรับผู้ให้บริการตรวจสอบสิทธิ์ตั้งแต่ 2 รายขึ้นไป (อาจรวมถึงการตรวจสอบสิทธิ์แบบไม่ระบุชื่อ) ให้กับแอปของคุณ

หากต้องการเชื่อมโยงข้อมูลประจำตัวของผู้ให้บริการรับรองความถูกต้องกับบัญชีผู้ใช้ที่มีอยู่:

  1. ลงชื่อเข้าใช้ผู้ใช้โดยใช้ผู้ให้บริการหรือวิธีการตรวจสอบความถูกต้อง
  2. ดำเนินการขั้นตอนการลงชื่อเข้าใช้สำหรับผู้ให้บริการการตรวจสอบสิทธิ์รายใหม่ให้เสร็จสมบูรณ์ แต่ไม่รวมการเรียกหนึ่งในเมธอด FIRAuth.signInWith ตัวอย่างเช่น รับโทเค็น Google ID ของผู้ใช้, โทเค็นการเข้าถึง Facebook หรืออีเมลและรหัสผ่าน
  3. รับ FIRAuthCredential สำหรับผู้ให้บริการการตรวจสอบความถูกต้องรายใหม่:

    ลงชื่อเข้าใช้ Google
    สวิฟท์
    guard
      let authentication = user?.authentication,
      let idToken = authentication.idToken
    else {
      return
    }
    
    let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                   accessToken: authentication.accessToken)
    
    วัตถุประสงค์-C
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:result.user.idToken.tokenString
                                     accessToken:result.user.accessToken.tokenString];
    
    เข้าสู่ระบบเฟสบุ๊ค
    สวิฟท์
    let credential = FacebookAuthProvider
      .credential(withAccessToken: AccessToken.current!.tokenString)
    
    วัตถุประสงค์-C
    FIRAuthCredential *credential = [FIRFacebookAuthProvider
        credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    
    ลงชื่อเข้าใช้ด้วยอีเมลและรหัสผ่าน
    สวิฟท์
    let credential = EmailAuthProvider.credential(withEmail: email, password: password)
    
    วัตถุประสงค์-C
    FIRAuthCredential *credential =
        [FIREmailAuthProvider credentialWithEmail:email
                                                 password:password];
    
  4. ส่งผ่านออบเจ็กต์ FIRAuthCredential ไปยังเมธอด linkWithCredential:completion: ของผู้ใช้ที่ลงชื่อเข้าใช้:

    สวิฟท์
        user.link(with: credential) { authResult, error in
      // ...
    }
    }
    
    วัตถุประสงค์-C
        [[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
                // ...
            }
    

    วัตถุประสงค์-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

สวิฟท์

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

วัตถุประสงค์-C

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