يمكنك السماح للمستخدمين بالمصادقة باستخدام Firebase من خلال حساباتهم على Facebook عن طريق دمج ميزة "تسجيل الدخول باستخدام Facebook" أو ميزة "تسجيل الدخول المحدود باستخدام Facebook" في تطبيقك.
قبل البدء
استخدِم Swift Package Manager لتثبيت التبعيات في Firebase وإدارتها.
- في Xcode، افتح مشروع تطبيقك وانتقِل إلى ملف > إضافة حِزم.
- عندما يُطلب منك ذلك، أضِف مستودع حزمة تطوير البرامج (SDK) لمنصات Firebase على Apple:
- اختَر مكتبة Firebase Authentication.
- أضِف العلامة
-ObjCإلى قسم علامات الرابط الأخرى في إعدادات الإصدار للهدف. - بعد الانتهاء، سيبدأ Xcode تلقائيًا في حلّ التبعيات وتنزيلها في الخلفية.
https://github.com/firebase/firebase-ios-sdk.git
بعد ذلك، اتّبِع بعض خطوات الضبط:
- على موقع Facebook للمطوّرين ، احصل على معرّف التطبيق وسر التطبيق لتطبيقك.
- فعِّل ميزة "تسجيل الدخول باستخدام Facebook":
- في وحدة تحكّم Firebaseconsole، افتح قسم المصادقة.
- في علامة التبويب طريقة تسجيل الدخول ، فعِّل طريقة تسجيل الدخول Facebook وحدِّد معرّف التطبيق وسر التطبيق اللذين حصلت عليهما من Facebook.
- بعد ذلك، تأكَّد من أنّ معرّف URI لإعادة توجيه OAuth (مثل
my-app-12345.firebaseapp.com/__/auth/handler) مدرَج كأحد معرّفات URI لإعادة توجيه OAuth في صفحة إعدادات تطبيقك على Facebook في موقع Facebook للمطوّرين ضمن إعدادات إعدادات المنتج > تسجيل الدخول باستخدام Facebook.
تنفيذ ميزة "تسجيل الدخول باستخدام Facebook"
لاستخدام ميزة "تسجيل الدخول باستخدام Facebook" "الكلاسيكية"، أكمِل الخطوات التالية. بدلاً من ذلك، يمكنك استخدام ميزة "تسجيل الدخول المحدود باستخدام 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 وAuthenticationSwiftUI
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"
لاستخدام ميزة "تسجيل الدخول المحدود باستخدام Facebook" بدلاً من ميزة "تسجيل الدخول باستخدام Facebook" "الكلاسيكية"، أكمِل الخطوات التالية.
- يمكنك دمج ميزة "تسجيل الدخول المحدود باستخدام Facebook" في تطبيقك باتّباع مستندات المطوّرين.
- لكل طلب تسجيل دخول، أنشِئ سلسلة عشوائية فريدة، وهي "رقم خاص"، ستستخدمها للتأكّد من أنّ الرمز المميّز للمعرّف الذي تحصل عليه تم منحه استجابةً لطلب المصادقة في تطبيقك على وجه التحديد. هذه الخطوة مهمة لـ
منع هجمات إعادة التشغيل.
يمكنك إنشاء قيمة عشوائية آمنة مشفّرة باستخدام
SecRandomCopyBytes(_:_:_)، كما في المثال التالي:سترِسل تجزئة SHA-256 للقيمة العشوائية مع طلب تسجيل الدخول، والتي سيُمرِّرها Facebook بدون تغيير في الردّ. تتحقّق Firebase من الردّ عن طريق تجزئة الرقم الخاص الأصلي ومقارنته بالقيمة التي مرّرها Facebook.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 وAuthenticationSwiftUI
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() } } } }
- بعد أن يُسجِّل المستخدم الدخول بنجاح، استخدِم الرمز المميّز للمعرّف من ردّ Facebook مع الرقم الخاص غير المشفّر للحصول على بيانات اعتماد 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; }
قد تحتاج أيضًا إلى إضافة رمز للتعامل مع الأخطاء من أجل النطاق الكامل لأخطاء المصادقة. اطّلِع على التعامل مع الأخطاء.