אתם יכולים לאפשר למשתמשים שלכם לעבור אימות ב-Firebase באמצעות חשבונות הפייסבוק שלהם על ידי שילוב של התחברות באמצעות פייסבוק או התחברות מוגבלת באמצעות פייסבוק באפליקציה שלכם.
לפני שמתחילים
משתמשים ב-Swift Package Manager כדי להתקין ולנהל יחסי תלות ב-Firebase.
- ב-Xcode, כשפרויקט האפליקציה פתוח, עוברים אל File > Add Packages (קובץ > הוספת חבילות).
- כשמוצגת בקשה, מוסיפים את מאגר Firebase Apple platforms SDK:
- בוחרים את הספרייה Firebase Authentication.
- מוסיפים את הדגל
-ObjCלקטע Other Linker Flags בהגדרות הבנייה של יעד הקישור. - אחרי שתסיימו, פלטפורמת Xcode תתחיל באופן אוטומטי לטפל ביחסי התלות ולהוריד אותם ברקע.
https://github.com/firebase/firebase-ios-sdk.git
לאחר מכן, מבצעים כמה שלבי הגדרה:
- באתר Facebook for Developers, מאתרים את App ID ואת App Secret של האפליקציה.
- הפעלת התחברות באמצעות Facebook:
- במסוף Firebase, פותחים את הקטע Authentication.
- בכרטיסייה שיטת הכניסה, מפעילים את שיטת הכניסה Facebook ומציינים את מזהה האפליקציה ואת סוד האפליקציה שקיבלתם מ-Facebook.
- לאחר מכן, מוודאים שכתובת ה-URI להפניה אוטומטית של OAuth (לדוגמה,
my-app-12345.firebaseapp.com/__/auth/handler) מופיעה כאחת מכתובות ה-URI להפניה אוטומטית של OAuth בדף ההגדרות של אפליקציית פייסבוק באתר Facebook for Developers בהגדרה Product Settings > Facebook Login.
הטמעה של התכונה 'התחברות באמצעות חשבון Facebook'
כדי להשתמש בגרסה הקלאסית של התכונה 'כניסה באמצעות פייסבוק', צריך לבצע את השלבים הבאים. לחלופין, אפשר להשתמש בכניסה מוגבלת ל-Facebook, כמו שמוסבר בקטע הבא.
- כדי לשלב את התכונה 'כניסה באמצעות פייסבוק' באפליקציה, פועלים לפי ההוראות
בתיעוד למפתחים. כשמפעילים את האובייקט
FBSDKLoginButton, מגדירים נציג לקבלת אירועי התחברות והתנתקות. לדוגמה:בנציג, מטמיעים אתSwift
let loginButton = FBSDKLoginButton() loginButton.delegate = self
Objective-C
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init]; loginButton.delegate = self;
didCompleteWithResult:error:.Swift
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) { if let error = error { print(error.localizedDescription) return } // ... }
Objective-C
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error { if (error == nil) { // ... } else { NSLog(error.localizedDescription); } }
- מייבאים את המודול
FirebaseCoreב-UIApplicationDelegate, וגם את כל מודולי Firebase אחרים שמשמשים את נציג האפליקציה. לדוגמה, כדי להשתמש ב-Cloud Firestore וב-Authentication:SwiftUI
import SwiftUI import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Swift
import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Objective-C
@import FirebaseCore; @import FirebaseFirestore; @import FirebaseAuth; // ...
- מגדירים מופע משותף בשיטה
application(_:didFinishLaunchingWithOptions:)של נציג האפליקציה:FirebaseAppSwiftUI
// Use Firebase library to configure APIs FirebaseApp.configure()
Swift
// Use Firebase library to configure APIs FirebaseApp.configure()
Objective-C
// Use Firebase library to configure APIs [FIRApp configure];
- אם אתם משתמשים ב-SwiftUI, אתם צריכים ליצור נציג אפליקציה ולצרף אותו למבנה
AppבאמצעותUIApplicationDelegateAdaptorאוNSApplicationDelegateAdaptor. צריך גם להשבית את החלפת הפונקציות של נציג האפליקציה. מידע נוסף זמין בהוראות ל-SwiftUI.SwiftUI
@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:Swift
let credential = FacebookAuthProvider .credential(withAccessToken: AccessToken.current!.tokenString)
Objective-C
FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
הטמעה של כניסה מוגבלת באמצעות Facebook
כדי להשתמש ב'כניסה מוגבלת דרך פייסבוק' במקום ב'כניסה קלאסית דרך פייסבוק', צריך לבצע את השלבים הבאים.
- כדי לשלב את הכניסה המוגבלת של פייסבוק באפליקציה, פועלים לפי התיעוד למפתחים.
- לכל בקשת כניסה, יוצרים מחרוזת אקראית ייחודית – 'ערך חד-פעמי' – שבה משתמשים כדי לוודא שטוקן הזהות שמתקבל הוענק בתגובה ספציפית לבקשת האימות של האפליקציה. השלב הזה חשוב כדי למנוע התקפות שליחה מחדש.
אפשר ליצור ערך חד-פעמי מאובטח מבחינה קריפטוגרפית באמצעות
SecRandomCopyBytes(_:_:_), כמו בדוגמה הבאה:תשלחו את גיבוב SHA-256 של המספר החד-פעמי עם בקשת הכניסה, ופייסבוק תעביר אותו ללא שינוי בתשובה. Firebase מאמת את התגובה על ידי גיבוב של ה-nonce המקורי והשוואה שלו לערך שמועבר על ידי פייסבוק.Swift
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) }
Objective-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]; }
Swift
@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 }
Objective-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ולצרף ערך חד-פעמי. לדוגמה:בנציג, מטמיעים אתSwift
func setupLoginButton() { let nonce = randomNonceString() currentNonce = nonce loginButton.delegate = self loginButton.loginTracking = .limited loginButton.nonce = sha256(nonce) }
Objective-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:.Swift
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) { if let error = error { print(error.localizedDescription) return } // ... }
Objective-C
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error { if (error == nil) { // ... } else { NSLog(error.localizedDescription); } }
- מייבאים את המודול
FirebaseCoreב-UIApplicationDelegate, וגם את כל מודולי Firebase אחרים שמשמשים את נציג האפליקציה. לדוגמה, כדי להשתמש ב-Cloud Firestore וב-Authentication:SwiftUI
import SwiftUI import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Swift
import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Objective-C
@import FirebaseCore; @import FirebaseFirestore; @import FirebaseAuth; // ...
- מגדירים מופע משותף בשיטה
application(_:didFinishLaunchingWithOptions:)של נציג האפליקציה:FirebaseAppSwiftUI
// Use Firebase library to configure APIs FirebaseApp.configure()
Swift
// Use Firebase library to configure APIs FirebaseApp.configure()
Objective-C
// Use Firebase library to configure APIs [FIRApp configure];
- אם אתם משתמשים ב-SwiftUI, אתם צריכים ליצור נציג אפליקציה ולצרף אותו למבנה
AppבאמצעותUIApplicationDelegateAdaptorאוNSApplicationDelegateAdaptor. צריך גם להשבית את החלפת הפונקציות של נציג האפליקציה. מידע נוסף זמין בהוראות ל-SwiftUI.SwiftUI
@main struct YourApp: App { // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { NavigationView { ContentView() } } } }
- אחרי שהמשתמש נכנס לחשבון בהצלחה, צריך להשתמש באסימון המזהה מהתגובה של פייסבוק עם ה-nonce שלא עבר גיבוב כדי לקבל אישור גישה ל-Firebase, בהטמעה של
didCompleteWithResult:error::Swift
// Initialize a Firebase credential. let idTokenString = AuthenticationToken.current?.tokenString let nonce = currentNonce let credential = OAuthProvider.credential(withProviderID: "facebook.com", idToken: idTokenString!, rawNonce: nonce)
Objective-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:
Swift
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 // ... }
Objective-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 כללי האבטחה, אפשר לקבל את מזהה המשתמש הייחודי של המשתמש המחובר מהמשתנה
auth, ולהשתמש בו כדי לקבוע לאילו נתונים המשתמש יכול לגשת.
אתם יכולים לאפשר למשתמשים להיכנס לאפליקציה שלכם באמצעות כמה ספקי אימות על ידי קישור פרטי כניסה של ספק אימות לחשבון משתמש קיים.
כדי להוציא משתמש מהחשבון, מתקשרים אל
signOut:.
Swift
let firebaseAuth = Auth.auth() do { try firebaseAuth.signOut() } catch let signOutError as NSError { print("Error signing out: %@", signOutError) }
Objective-C
NSError *signOutError; BOOL status = [[FIRAuth auth] signOut:&signOutError]; if (!status) { NSLog(@"Error signing out: %@", signOutError); return; }
כדאי גם להוסיף קוד לטיפול בשגיאות לכל טווח השגיאות של האימות. מידע נוסף זמין במאמר בנושא טיפול בשגיאות.