คุณสามารถให้ผู้ใช้รับรองความถูกต้องกับ Firebase โดยใช้บัญชี Facebook ของพวกเขาได้โดยการรวมการเข้าสู่ระบบด้วย Facebook หรือการเข้าสู่ระบบแบบ จำกัด ของ Facebook เข้ากับแอพของคุณ
ก่อนที่คุณจะเริ่มต้น
ใช้ Swift Package Manager เพื่อติดตั้งและจัดการการอ้างอิง Firebase
- ใน Xcode เมื่อโปรเจ็กต์แอปของคุณเปิดอยู่ ให้ไปที่ File > Add Packages
- เมื่อได้รับแจ้ง ให้เพิ่มที่เก็บ Firebase Apple platforms SDK:
- เลือกไลบรารีการรับรองความถูกต้องของ Firebase
- เมื่อเสร็จแล้ว Xcode จะเริ่มแก้ไขและดาวน์โหลดการอ้างอิงของคุณโดยอัตโนมัติในเบื้องหลัง
https://github.com/firebase/firebase-ios-sdk
ถัดไป ดำเนินการตามขั้นตอนการกำหนดค่า:
- บนไซต์ Facebook for Developers ให้รับ App ID และ App Secret สำหรับแอพของคุณ
- เปิดใช้งานการเข้าสู่ระบบ Facebook:
- ใน คอนโซล Firebase ให้เปิดส่วน การรับรองความถูกต้อง
- บน แท็บ วิธีการลงชื่อเข้า ใช้ ให้เปิดใช้งานวิธีการลงชื่อเข้าใช้ Facebook และระบุ App ID และ App Secret ที่คุณได้รับจาก Facebook
- จากนั้น ตรวจสอบให้แน่ใจว่า URI การเปลี่ยนเส้นทาง OAuth ของคุณ (เช่น
my-app-12345.firebaseapp.com/__/auth/handler
) แสดงเป็นหนึ่งใน URI การเปลี่ยนเส้นทาง OAuth ของคุณในหน้าการตั้งค่าของแอพ Facebook บนเว็บไซต์ Facebook for Developers ใน ผลิตภัณฑ์ การตั้งค่า > การกำหนดค่าการเข้าสู่ระบบ Facebook
ใช้การเข้าสู่ระบบ Facebook
หากต้องการใช้การเข้าสู่ระบบ Facebook แบบ "คลาสสิก" ให้ทำตามขั้นตอนต่อไปนี้ หรือคุณสามารถใช้ Facebook Limited Login ดังที่แสดงในหัวข้อถัดไป
- รวมการเข้าสู่ระบบด้วย 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); } }
- นำเข้าโมดูล
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; // ...
- กำหนดค่าอินสแตนซ์ที่ใช้ร่วมกันของ
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];
- หากคุณใช้ SwiftUI คุณต้องสร้างตัวแทนแอปพลิเคชันและแนบกับโครงสร้าง
App
ของคุณผ่านUIApplicationDelegateAdaptor
หรือNSApplicationDelegateAdaptor
คุณต้องปิดใช้งานการ swizzling ของผู้รับมอบสิทธิ์แอปด้วย สำหรับข้อมูลเพิ่มเติม โปรดดู คำแนะนำ SwiftUISwiftUI
@main struct YourApp: App { // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { NavigationView { ContentView() } } } }
- หลังจากที่ผู้ใช้ลงชื่อเข้าใช้สำเร็จ ในการใช้งาน
didCompleteWithResult:error:
รับโทเค็นการเข้าถึงสำหรับผู้ใช้ที่ลงชื่อเข้าใช้และแลกเปลี่ยนเป็นข้อมูลรับรอง Firebase:สวิฟต์
let credential = FacebookAuthProvider .credential(withAccessToken: AccessToken.current!.tokenString)
วัตถุประสงค์-C
FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
ใช้การเข้าสู่ระบบแบบ จำกัด ของ Facebook
หากต้องการใช้การเข้าสู่ระบบแบบจำกัดด้วย Facebook แทนการเข้าสู่ระบบด้วย Facebook แบบ "คลาสสิก" ให้ทำตามขั้นตอนต่อไปนี้
- รวมการเข้าสู่ระบบ Facebook Limited เข้ากับแอพของคุณโดยทำตาม เอกสารประกอบของผู้พัฒนา
- สำหรับทุกคำขอลงชื่อเข้าใช้ ให้สร้างสตริงสุ่มที่ไม่ซ้ำกัน ซึ่งก็คือ "nonce" ซึ่งคุณจะใช้เพื่อให้แน่ใจว่าโทเค็น ID ที่คุณได้รับนั้นได้รับโดยเฉพาะเพื่อตอบสนองคำขอการตรวจสอบสิทธิ์ของแอป ขั้นตอนนี้มีความสำคัญในการป้องกันการโจมตีซ้ำ คุณสามารถสร้าง nonce ที่ปลอดภัยด้วยการเข้ารหัสด้วย
SecRandomCopyBytes(_:_:_)
ดังตัวอย่างต่อไปนี้:คุณจะส่งแฮช SHA-256 ของ nonce พร้อมกับคำขอลงชื่อเข้าใช้ ซึ่ง Facebook จะตอบกลับโดยไม่เปลี่ยนแปลง Firebase ตรวจสอบการตอบสนองโดยแฮช nonce ดั้งเดิมและเปรียบเทียบกับค่าที่ Facebook ส่งมาสวิฟต์
private func randomNonceString(length: Int = 32) -> String { precondition(length > 0) var randomBytes = [UInt8](repeating: 0, count: length) let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) if errorCode != errSecSuccess { fatalError( "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)" ) } let charset: [Character] = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") let nonce = randomBytes.map { byte in // Pick a random character from the set, wrapping around if needed. charset[Int(byte) % charset.count] } return String(nonce) }
วัตถุประสงค์-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]; }
สวิฟต์
@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; }
- เมื่อคุณตั้งค่า
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); } }
- นำเข้าโมดูล
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; // ...
- กำหนดค่าอินสแตนซ์ที่ใช้ร่วมกันของ
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];
- หากคุณใช้ SwiftUI คุณต้องสร้างตัวแทนแอปพลิเคชันและแนบกับโครงสร้าง
App
ของคุณผ่านUIApplicationDelegateAdaptor
หรือNSApplicationDelegateAdaptor
คุณต้องปิดใช้งานการ swizzling ของผู้รับมอบสิทธิ์แอปด้วย สำหรับข้อมูลเพิ่มเติม โปรดดู คำแนะนำ SwiftUISwiftUI
@main struct YourApp: App { // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { NavigationView { ContentView() } } } }
- หลังจากที่ผู้ใช้ลงชื่อเข้าใช้สำเร็จ ในการใช้งาน
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; }
คุณอาจต้องการเพิ่มรหัสการจัดการข้อผิดพลาดสำหรับข้อผิดพลาดการตรวจสอบสิทธิ์ทั้งหมด ดู จัดการข้อผิดพลาด