Liên kết nhiều nhà cung cấp xác thực với một tài khoản trên nền tảng Apple

Bạn có thể cho phép người dùng đăng nhập vào ứng dụng của mình bằng nhiều nhà cung cấp xác thực bằng cách liên kết thông tin xác thực của nhà cung cấp xác thực với tài khoản người dùng hiện có. Người dùng có thể được nhận dạng bằng cùng một ID người dùng Firebase bất kể nhà cung cấp xác thực mà họ đã sử dụng để đăng nhập. Ví dụ: người dùng đã đăng nhập bằng mật khẩu có thể liên kết tài khoản Google và đăng nhập bằng một trong hai phương pháp trong tương lai. Hoặc, người dùng ẩn danh có thể liên kết tài khoản Facebook và sau đó đăng nhập bằng Facebook để tiếp tục sử dụng ứng dụng của bạn.

Trước khi bắt đầu

Thêm hỗ trợ cho hai hoặc nhiều nhà cung cấp xác thực (có thể bao gồm xác thực ẩn danh) vào ứng dụng của bạn.

Để liên kết thông tin đăng nhập của nhà cung cấp xác thực với tài khoản người dùng hiện có:

  1. Đăng nhập người dùng bằng bất kỳ nhà cung cấp hoặc phương thức xác thực nào.
  2. Hoàn tất quy trình đăng nhập cho nhà cung cấp xác thực mới tối đa nhưng không bao gồm việc gọi một trong các phương thức FIRAuth.signInWith . Ví dụ: lấy mã thông báo Google ID, mã thông báo truy cập Facebook hoặc email và mật khẩu của người dùng.
  3. Nhận FIRAuthCredential cho nhà cung cấp xác thực mới:

    Đăng nhập bằng Google
    Nhanh
    guard
      let authentication = user?.authentication,
      let idToken = authentication.idToken
    else {
      return
    }
    
    let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                   accessToken: authentication.accessToken)
    
    Mục tiêu-C
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:result.user.idToken.tokenString
                                     accessToken:result.user.accessToken.tokenString];
    
    Đăng nhập Facebook
    Nhanh
    let credential = FacebookAuthProvider
      .credential(withAccessToken: AccessToken.current!.tokenString)
    
    Mục tiêu-C
    FIRAuthCredential *credential = [FIRFacebookAuthProvider
        credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    
    Đăng nhập bằng mật khẩu email
    Nhanh
    let credential = EmailAuthProvider.credential(withEmail: email, password: password)
    
    Mục tiêu-C
    FIRAuthCredential *credential =
        [FIREmailAuthProvider credentialWithEmail:email
                                                 password:password];
    
  4. Truyền đối tượng FIRAuthCredential tới phương thức linkWithCredential:completion: của người dùng đã đăng nhập:

    Nhanh
        user.link(with: credential) { authResult, error in
      // ...
    }
    }
    
    Mục tiêu-C
        [[FIRAuth auth].currentUser linkWithCredential:credential
        completion:^(FIRAuthDataResult *result, NSError *_Nullable error) {
      // ...
    }];
    

    Cuộc gọi tới linkWithCredential:completion: sẽ không thành công nếu thông tin xác thực đã được liên kết với tài khoản người dùng khác. Trong tình huống này, bạn phải xử lý việc hợp nhất các tài khoản và dữ liệu liên quan sao cho phù hợp với ứng dụng của mình:

    Nhanh

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

    Mục tiêu-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
                                        // ...
                                    }];
    

Nếu lệnh gọi tới linkWithCredential:completion: thành công thì giờ đây người dùng có thể đăng nhập bằng bất kỳ nhà cung cấp xác thực được liên kết nào và truy cập vào cùng một dữ liệu Firebase.

Bạn có thể hủy liên kết nhà cung cấp dịch vụ xác thực khỏi tài khoản để người dùng không thể đăng nhập bằng nhà cung cấp đó nữa.

Để hủy liên kết nhà cung cấp xác thực khỏi tài khoản người dùng, hãy chuyển ID nhà cung cấp sang phương thức unlink . Bạn có thể lấy ID nhà cung cấp của các nhà cung cấp dịch vụ xác thực được liên kết với người dùng từ thuộc tính providerData .

Nhanh

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

Mục tiêu-C

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