Firebase is back at Google I/O on May 10! Register now

ตรวจสอบสิทธิ์โดยใช้การเข้าสู่ระบบ Facebook บนแพลตฟอร์ม Apple

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

คุณสามารถให้ผู้ใช้รับรองความถูกต้องกับ Firebase โดยใช้บัญชี Facebook ของพวกเขาได้โดยการรวมการเข้าสู่ระบบด้วย Facebook หรือการเข้าสู่ระบบแบบ จำกัด ของ Facebook เข้ากับแอพของคุณ

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

ใช้ Swift Package Manager เพื่อติดตั้งและจัดการการอ้างอิง Firebase

  1. ใน Xcode เมื่อโปรเจ็กต์แอปของคุณเปิดอยู่ ให้ไปที่ File > Add Packages
  2. เมื่อได้รับแจ้ง ให้เพิ่มที่เก็บ Firebase Apple platforms SDK:
  3.   https://github.com/firebase/firebase-ios-sdk
  4. เลือกไลบรารีการรับรองความถูกต้องของ Firebase
  5. เมื่อเสร็จแล้ว Xcode จะเริ่มแก้ไขและดาวน์โหลดการอ้างอิงของคุณโดยอัตโนมัติในเบื้องหลัง

ถัดไป ดำเนินการตามขั้นตอนการกำหนดค่า:

  1. บนไซต์ Facebook for Developers ให้รับ App ID และ App Secret สำหรับแอพของคุณ
  2. เปิดใช้งานการเข้าสู่ระบบ Facebook:
    1. ใน คอนโซล Firebase ให้เปิดส่วนการ รับรอง ความถูกต้อง
    2. บนแท็บ วิธีการลงชื่อเข้า ใช้ ให้เปิดใช้งานวิธีการลงชื่อเข้าใช้ Facebook และระบุ App ID และ App Secret ที่คุณได้รับจาก Facebook
    3. จากนั้น ตรวจสอบให้แน่ใจว่า URI การเปลี่ยนเส้นทาง OAuth ของคุณ (เช่น my-app-12345.firebaseapp.com/__/auth/handler ) แสดงเป็นหนึ่งใน URI การเปลี่ยนเส้นทาง OAuth ของคุณในหน้าการตั้งค่าของแอพ Facebook บนเว็บไซต์ Facebook for Developers ใน ผลิตภัณฑ์ การตั้งค่า > การกำหนดค่าการเข้าสู่ระบบ Facebook

ใช้การเข้าสู่ระบบ Facebook

หากต้องการใช้การเข้าสู่ระบบ Facebook แบบ "คลาสสิก" ให้ทำตามขั้นตอนต่อไปนี้ หรือคุณสามารถใช้ Facebook Limited Login ดังที่แสดงในหัวข้อถัดไป

  1. รวมการเข้าสู่ระบบด้วย Facebook เข้ากับแอพของคุณโดยทำตาม เอกสารประกอบของผู้พัฒนา เมื่อคุณเริ่มต้นออบเจกต์ FBSDKLoginButton ให้ตั้งค่าผู้รับมอบสิทธิ์เพื่อรับเหตุการณ์การเข้าสู่ระบบและออกจากระบบ ตัวอย่างเช่น:

    สวิฟต์

    let loginButton = FBSDKLoginButton()
    loginButton.delegate = self
    

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

    FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init];
    loginButton.delegate = self;
    
    ในผู้รับมอบสิทธิ์ของคุณ ใช้ didCompleteWithResult:error:

    สวิฟต์

    func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
      if let error = error {
        print(error.localizedDescription)
        return
      }
      // ...
    }
    

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

    - (void)loginButton:(FBSDKLoginButton *)loginButton
        didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result
                        error:(NSError *)error {
      if (error == nil) {
        // ...
      } else {
        NSLog(error.localizedDescription);
      }
    }
    
  2. นำเข้าโมดูล FirebaseCore ใน UIApplicationDelegate ของคุณ รวมถึง โมดูล Firebase อื่นๆ ที่ตัวแทนแอปของคุณใช้ ตัวอย่างเช่น หากต้องการใช้ Cloud Firestore และการรับรองความถูกต้อง:

    SwiftUI

    import SwiftUI
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    สวิฟต์

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

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

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  3. กำหนดค่าอินสแตนซ์ที่ใช้ร่วมกันของ FirebaseApp ในแอปพลิเคชันผู้รับมอบสิทธิ์แอปของคุณ application(_:didFinishLaunchingWithOptions:) วิธีการ:

    SwiftUI

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    สวิฟต์

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

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

    // Use Firebase library to configure APIs
    [FIRApp configure];
  4. หากคุณใช้ SwiftUI คุณต้องสร้างตัวแทนแอปพลิเคชันและแนบกับโครงสร้าง App ของคุณผ่าน UIApplicationDelegateAdaptor หรือ NSApplicationDelegateAdaptor คุณต้องปิดใช้งานการ swizzling ของผู้รับมอบสิทธิ์แอปด้วย สำหรับข้อมูลเพิ่มเติม โปรดดู คำแนะนำ SwiftUI

    SwiftUI

    @main
    struct YourApp: App {
      // register app delegate for Firebase setup
      @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
      var body: some Scene {
        WindowGroup {
          NavigationView {
            ContentView()
          }
        }
      }
    }
          
  5. หลังจากที่ผู้ใช้ลงชื่อเข้าใช้สำเร็จ ในการใช้งาน didCompleteWithResult:error: รับโทเค็นการเข้าถึงสำหรับผู้ใช้ที่ลงชื่อเข้าใช้และแลกเปลี่ยนเป็นข้อมูลรับรอง Firebase:

    สวิฟต์

    let credential = FacebookAuthProvider
      .credential(withAccessToken: AccessToken.current!.tokenString)
    

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

    FIRAuthCredential *credential = [FIRFacebookAuthProvider
        credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
    

ใช้การเข้าสู่ระบบแบบ จำกัด ของ Facebook

หากต้องการใช้การเข้าสู่ระบบแบบจำกัดด้วย Facebook แทนการเข้าสู่ระบบด้วย Facebook แบบ "คลาสสิก" ให้ทำตามขั้นตอนต่อไปนี้

  1. รวมการเข้าสู่ระบบ Facebook Limited เข้ากับแอพของคุณโดยทำตาม เอกสารประกอบของผู้พัฒนา
  2. สำหรับทุกคำขอลงชื่อเข้าใช้ ให้สร้างสตริงสุ่มที่ไม่ซ้ำกัน ซึ่งก็คือ "nonce" ซึ่งคุณจะใช้เพื่อให้แน่ใจว่าโทเค็น ID ที่คุณได้รับนั้นได้รับโดยเฉพาะเพื่อตอบสนองคำขอการตรวจสอบสิทธิ์ของแอป ขั้นตอนนี้มีความสำคัญในการป้องกันการโจมตีซ้ำ คุณสามารถสร้าง nonce ที่ปลอดภัยด้วยการเข้ารหัสด้วย SecRandomCopyBytes(_:_:_) ดังตัวอย่างต่อไปนี้:

    สวิฟต์

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
      var result = ""
      var remainingLength = length
    
      while remainingLength > 0 {
        let randoms: [UInt8] = (0 ..< 16).map { _ in
          var random: UInt8 = 0
          let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
          if errorCode != errSecSuccess {
            fatalError(
              "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
            )
          }
          return random
        }
    
        randoms.forEach { random in
          if remainingLength == 0 {
            return
          }
    
          if random < charset.count {
            result.append(charset[Int(random)])
            remainingLength -= 1
          }
        }
      }
    
      return result
    }
    
            

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

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    - (NSString *)randomNonce:(NSInteger)length {
      NSAssert(length > 0, @"Expected nonce to have positive length");
      NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
      NSMutableString *result = [NSMutableString string];
      NSInteger remainingLength = length;
    
      while (remainingLength > 0) {
        NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
        for (NSInteger i = 0; i < 16; i++) {
          uint8_t random = 0;
          int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
          NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode);
    
          [randoms addObject:@(random)];
        }
    
        for (NSNumber *random in randoms) {
          if (remainingLength == 0) {
            break;
          }
    
          if (random.unsignedIntValue < characterSet.length) {
            unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
            [result appendFormat:@"%C", character];
            remainingLength--;
          }
        }
      }
    
      return [result copy];
    }
            
    คุณจะส่งแฮช SHA-256 ของ nonce พร้อมกับคำขอลงชื่อเข้าใช้ ซึ่ง Facebook จะตอบกลับโดยไม่เปลี่ยนแปลง Firebase ตรวจสอบการตอบสนองโดยแฮช nonce ดั้งเดิมและเปรียบเทียบกับค่าที่ Facebook ส่งมา

    สวิฟต์

    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
    
            

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

    - (NSString *)stringBySha256HashingString:(NSString *)input {
      const char *string = [input UTF8String];
      unsigned char result[CC_SHA256_DIGEST_LENGTH];
      CC_SHA256(string, (CC_LONG)strlen(string), result);
    
      NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
      for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [hashed appendFormat:@"%02x", result[i]];
      }
      return hashed;
    }
            
  3. เมื่อคุณตั้งค่า FBSDKLoginButton ให้ตั้งค่าผู้รับมอบสิทธิ์เพื่อรับเหตุการณ์การเข้าสู่ระบบและออกจากระบบ ตั้งค่าโหมดการติดตามเป็น FBSDKLoginTrackingLimited และแนบ nonce ตัวอย่างเช่น:

    สวิฟต์

    func setupLoginButton() {
        let nonce = randomNonceString()
        currentNonce = nonce
        loginButton.delegate = self
        loginButton.loginTracking = .limited
        loginButton.nonce = sha256(nonce)
    }
            

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

    - (void)setupLoginButton {
      NSString *nonce = [self randomNonce:32];
      self.currentNonce = nonce;
      self.loginButton.delegate = self;
      self.loginButton.loginTracking = FBSDKLoginTrackingLimited
      self.loginButton.nonce = [self stringBySha256HashingString:nonce];
    }
            
    ในผู้รับมอบสิทธิ์ของคุณ ใช้ didCompleteWithResult:error:

    สวิฟต์

    func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
      if let error = error {
        print(error.localizedDescription)
        return
      }
      // ...
    }
            

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

    - (void)loginButton:(FBSDKLoginButton *)loginButton
        didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result
                        error:(NSError *)error {
      if (error == nil) {
        // ...
      } else {
        NSLog(error.localizedDescription);
      }
    }
            
  4. นำเข้าโมดูล FirebaseCore ใน UIApplicationDelegate ของคุณ รวมถึง โมดูล Firebase อื่นๆ ที่ตัวแทนแอปของคุณใช้ ตัวอย่างเช่น หากต้องการใช้ Cloud Firestore และการรับรองความถูกต้อง:

    SwiftUI

    import SwiftUI
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    สวิฟต์

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

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

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  5. กำหนดค่าอินสแตนซ์ที่ใช้ร่วมกันของ FirebaseApp ในแอปพลิเคชันผู้รับมอบสิทธิ์แอปของคุณ application(_:didFinishLaunchingWithOptions:) วิธีการ:

    SwiftUI

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    สวิฟต์

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

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

    // Use Firebase library to configure APIs
    [FIRApp configure];
  6. หากคุณใช้ SwiftUI คุณต้องสร้างตัวแทนแอปพลิเคชันและแนบกับโครงสร้าง App ของคุณผ่าน UIApplicationDelegateAdaptor หรือ NSApplicationDelegateAdaptor คุณต้องปิดใช้งานการ swizzling ของผู้รับมอบสิทธิ์แอปด้วย สำหรับข้อมูลเพิ่มเติม โปรดดู คำแนะนำ SwiftUI

    SwiftUI

    @main
    struct YourApp: App {
      // register app delegate for Firebase setup
      @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
      var body: some Scene {
        WindowGroup {
          NavigationView {
            ContentView()
          }
        }
      }
    }
          
  7. หลังจากที่ผู้ใช้ลงชื่อเข้าใช้สำเร็จ ในการใช้งาน didCompleteWithResult:error: ให้ใช้โทเค็น ID จากการตอบกลับของ Facebook ด้วย nonce ที่ไม่ได้แฮชเพื่อรับข้อมูลรับรอง Firebase:

    สวิฟต์

    // Initialize a Firebase credential.
    let idTokenString = AuthenticationToken.current?.tokenString
    let nonce = currentNonce
    let credential = OAuthProvider.credential(withProviderID: "facebook.com",
                                              idToken: idTokenString!,
                                              rawNonce: nonce)
            

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

    // Initialize a Firebase credential.
    NSString *idTokenString = FBSDKAuthenticationToken.currentAuthenticationToken.tokenString;
    NSString *rawNonce = self.currentNonce;
    FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"facebook.com"
                                                                        IDToken:idTokenString
                                                                       rawNonce:rawNonce];
            

รับรองความถูกต้องด้วย Firebase

สุดท้าย รับรองความถูกต้องกับ Firebase โดยใช้ข้อมูลประจำตัวของ Firebase:

สวิฟต์

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

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

[[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;
  // ...
}];
    

ขั้นตอนถัดไป

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

  • ในแอปของคุณ คุณสามารถรับข้อมูลโปรไฟล์พื้นฐานของผู้ใช้ได้จากวัตถุ User ดู จัดการผู้ใช้

  • ใน กฎความปลอดภัย ของ Firebase Realtime Database และ Cloud Storage คุณสามารถรับ ID ผู้ใช้ที่ไม่ซ้ำกันของผู้ใช้ที่ลงชื่อเข้าใช้จากตัวแปร auth ความถูกต้อง และใช้เพื่อควบคุมข้อมูลที่ผู้ใช้สามารถเข้าถึงได้

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

หากต้องการออกจากระบบผู้ใช้ ให้เรียก signOut:

สวิฟต์

let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print("Error signing out: %@", signOutError)
}

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

NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

คุณอาจต้องการเพิ่มรหัสการจัดการข้อผิดพลาดสำหรับข้อผิดพลาดการตรวจสอบสิทธิ์ทั้งหมด ดู จัดการข้อผิดพลาด