Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

المصادقة باستخدام Apple على iOS

يمكنك السماح للمستخدمين بالمصادقة مع Firebase باستخدام معرف Apple الخاص بهم باستخدام Firebase SDK لتنفيذ تدفق تسجيل الدخول من طرف إلى طرف OAuth 2.0.

قبل ان تبدأ

لتسجيل دخول المستخدمين باستخدام Apple ، قم أولاً بتكوين Sign In with Apple على موقع مطوري Apple ، ثم قم بتمكين Apple كموفر تسجيل الدخول لمشروع Firebase الخاص بك.

انضم إلى برنامج Apple Developer

تسجيل الدخول مع يمكن تكوين أبل فقط من قبل أعضاء المطور أبل برنامج .

قم بتكوين تسجيل الدخول مع Apple

  1. تمكين تسجيل الدخول مع أبل عن تطبيقك على شهادات، بطاقات الهوية والملامح صفحة من موقع أبل المطور.
  2. إذا كنت تستخدم أي من الميزات مصادقة Firebase أن ترسل رسائل البريد الإلكتروني للمستخدمين، بما في ذلك البريد الإلكتروني رابط تسجيل الدخول، التحقق من عنوان البريد الإلكتروني، وتغيير حساب الإلغاء، وغيرها، و تكوين خدمة الترحيل البريد الإلكتروني الخاصة أبل وتسجيل noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (أو مجال قالب البريد الإلكتروني المخصص الخاص بك) حتى تتمكن Apple من ترحيل رسائل البريد الإلكتروني المرسلة بواسطة مصادقة Firebase إلى عناوين بريد إلكتروني مجهولة الهوية من Apple.

قم بتمكين Apple كموفر لتسجيل الدخول

  1. إضافة إلى Firebase المشروع الذي يعمل بنظام iOS . تأكد من تسجيل معرف حزمة تطبيقك عند إعداد تطبيقك في وحدة تحكم Firebase.
  2. في وحدة التحكم Firebase ، فتح الباب أصيل. على علامة التبويب تسجيل الدخول الأسلوب، تمكين مزود أبل. إذا كنت تستخدم تسجيل الدخول مع Apple فقط في تطبيق iOS ، فيمكنك ترك معرف الخدمة ومعرف فريق Apple والمفتاح الخاص ومعرف المفتاح فارغين.

الامتثال لمتطلبات البيانات المجهولة الهوية من Apple

تسجيل الدخول مع أبل تتيح للمستخدمين خيار إخفاء الهوية البيانات الخاصة بهم، بما في ذلك عناوين بريدهم الإلكتروني، عند تسجيل الدخول. المستخدمين الذين يختارون هذا الخيار يكون عناوين البريد الإلكتروني مع المجال privaterelay.appleid.com . عند استخدام تسجيل الدخول مع Apple في تطبيقك ، يجب عليك الامتثال لأي سياسات مطور أو شروط مطبقة من Apple فيما يتعلق بمعرفات Apple المجهولة الهوية.

يتضمن ذلك الحصول على أي موافقة مطلوبة من المستخدم قبل ربط أي معلومات شخصية تحدد الهوية مباشرة بمعرف Apple المجهول. عند استخدام مصادقة Firebase ، قد يشمل ذلك الإجراءات التالية:

  • اربط عنوان بريد إلكتروني بمعرف Apple المجهول أو العكس.
  • اربط رقم هاتف بمعرف Apple المجهول أو العكس
  • اربط بيانات اعتماد اجتماعية غير مجهولة (Facebook ، Google ، إلخ) بمعرف Apple مجهول أو العكس.

القائمة أعلاه ليست شاملة. راجع اتفاقية ترخيص برنامج مطوري Apple في قسم العضوية لحساب المطور الخاص بك للتأكد من أن تطبيقك يلبي متطلبات Apple.

سجّل الدخول باستخدام Apple وقم بالمصادقة باستخدام Firebase

المصادقة مع حساب أبل، وأول علامة على أن المستعمل في لأبل على حساب باستخدام أبل AuthenticationServices الإطار ، ومن ثم استخدام معرف رمزية من استجابة أبل لإنشاء Firebase AuthCredential الكائن:

  1. لكل طلب تسجيل دخول ، أنشئ سلسلة عشوائية - "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
    }
    
        

    ج موضوعية

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

    سوف ترسل تجزئة SHA256 لـ nonce مع طلب تسجيل الدخول الخاص بك ، والذي ستمرره Apple دون تغيير في الاستجابة. يتحقق Firebase من الاستجابة عن طريق تجزئة الرقم الأصلي غير القياسي ومقارنته بالقيمة التي تم تمريرها بواسطة Apple.

    سويفت

    @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
    }
    
        

    ج موضوعية

    - (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;
    }
        
  2. ابدأ تدفق تسجيل الدخول إلى Apple ، بما في ذلك في طلبك تجزئة SHA256 لفئة nonce وفئة المفوض التي ستتعامل مع استجابة Apple (انظر الخطوة التالية):

    سويفت

    import CryptoKit
    
    // Unhashed nonce.
    fileprivate var currentNonce: String?
    
    @available(iOS 13, *)
    func startSignInWithAppleFlow() {
      let nonce = randomNonceString()
      currentNonce = nonce
      let appleIDProvider = ASAuthorizationAppleIDProvider()
      let request = appleIDProvider.createRequest()
      request.requestedScopes = [.fullName, .email]
      request.nonce = sha256(nonce)
    
      let authorizationController = ASAuthorizationController(authorizationRequests: [request])
      authorizationController.delegate = self
      authorizationController.presentationContextProvider = self
      authorizationController.performRequests()
    }
    

    ج موضوعية

    @import CommonCrypto;
    
    - (void)startSignInWithAppleFlow {
      NSString *nonce = [self randomNonce:32];
      self.currentNonce = nonce;
      ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
      ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];
      request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
      request.nonce = [self stringBySha256HashingString:nonce];
    
      ASAuthorizationController *authorizationController =
          [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
      authorizationController.delegate = self;
      authorizationController.presentationContextProvider = self;
      [authorizationController performRequests];
    }
    
  3. التعامل مع استجابة أبل في التطبيق الخاص بك من ASAuthorizationControllerDelegate . إذا كان تسجيل الدخول ناجحًا ، فاستخدم رمز المعرف المميز من استجابة Apple مع nonce غير المجزأ للمصادقة مع Firebase:

    سويفت

    @available(iOS 13.0, *)
    extension MainViewController: ASAuthorizationControllerDelegate {
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
          guard let nonce = currentNonce else {
            fatalError("Invalid state: A login callback was received, but no login request was sent.")
          }
          guard let appleIDToken = appleIDCredential.identityToken else {
            print("Unable to fetch identity token")
            return
          }
          guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
            return
          }
          // Initialize a Firebase credential.
          let credential = OAuthProvider.credential(withProviderID: "apple.com",
                                                    IDToken: idTokenString,
                                                    rawNonce: nonce)
          // Sign in with Firebase.
          Auth.auth().signIn(with: credential) { (authResult, error) in
            if error {
              // Error. If error.code == .MissingOrInvalidNonce, make sure
              // you're sending the SHA256-hashed nonce as a hex string with
              // your request to Apple.
              print(error.localizedDescription)
              return
            }
            // User is signed in to Firebase with Apple.
            // ...
          }
        }
      }
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Sign in with Apple errored: \(error)")
      }
    
    }
    

    ج موضوعية

    - (void)authorizationController:(ASAuthorizationController *)controller
       didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
      if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
        ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
        NSString *rawNonce = self.currentNonce;
        NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent.");
    
        if (appleIDCredential.identityToken == nil) {
          NSLog(@"Unable to fetch identity token.");
          return;
        }
    
        NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken
                                                  encoding:NSUTF8StringEncoding];
        if (idToken == nil) {
          NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken);
        }
    
        // Initialize a Firebase credential.
        FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
                                                                            IDToken:idToken
                                                                           rawNonce:rawNonce];
    
        // Sign in with Firebase.
        [[FIRAuth auth] signInWithCredential:credential
                                  completion:^(FIRAuthDataResult * _Nullable authResult,
                                               NSError * _Nullable error) {
          if (error != nil) {
            // Error. If error.code == FIRAuthErrorCodeMissingOrInvalidNonce,
            // make sure you're sending the SHA256-hashed nonce as a hex string
            // with your request to Apple.
            return;
          }
          // Sign-in succeeded!
        }];
      }
    }
    
    - (void)authorizationController:(ASAuthorizationController *)controller
               didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
      NSLog(@"Sign in with Apple errored: %@", error);
    }
    

على عكس الموفرين الآخرين المدعومين من Firebase Auth ، لا تقدم Apple عنوان URL للصورة.

أيضا، عندما يختار المستخدم ليس لتبادل البريد الإلكتروني الخاصة بهم مع التطبيق، أحكام أبل عنوان بريد إلكتروني فريد لهذا المستخدم (النموذج xyz@privaterelay.appleid.com )، وهو ما أسهم مع التطبيق الخاص بك. إذا قمت بتكوين خدمة ترحيل البريد الإلكتروني الخاص ، فإن Apple تعيد توجيه رسائل البريد الإلكتروني المرسلة إلى العنوان المجهول إلى عنوان البريد الإلكتروني الحقيقي للمستخدم.

التفاح المعلومات سهم فقط المستخدم مثل اسم العرض مع التطبيقات أول مرة قيام المستخدم بتسجيل الدخول. عادة، Firebase مخازن اسم العرض أول مرة قيام المستخدم بتسجيل الدخول مع أبل، والتي يمكنك الحصول عليها مع Auth.auth().currentUser.displayName . ومع ذلك ، إذا سبق لك استخدام Apple لتسجيل دخول مستخدم إلى التطبيق دون استخدام Firebase ، فلن تقدم Apple اسم عرض المستخدم لـ Firebase.

إعادة المصادقة وربط الحساب

على نفس النمط يمكن استخدامها مع reauthenticateWithCredential() ، والتي يمكنك استخدامها لاسترداد الاعتماد جديدة لعمليات الحساسة التي تتطلب مؤخرا تسجيل الدخول:

سويفت

// Initialize a fresh Apple credential with Firebase.
let credential = OAuthProvider.credential(
  withProviderID: "apple.com",
  IDToken: appleIdToken,
  rawNonce: rawNonce
)
// Reauthenticate current Apple user with fresh Apple credential.
Auth.auth().currentUser.reauthenticate(with: credential) { (authResult, error) in
  guard error != nil else { return }
  // Apple user successfully re-authenticated.
  // ...
}

ج موضوعية

FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com",
                                                                   IDToken:appleIdToken,
                                                                  rawNonce:rawNonce];
[[FIRAuth auth].currentUser
    reauthenticateWithCredential:credential
                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                   NSError * _Nullable error) {
  if (error) {
    // Handle error.
  }
  // Apple user successfully re-authenticated.
  // ...
}];

و، يمكنك استخدام linkWithCredential() لربط مقدمي هوية مختلفة لحسابات القائمة.

لاحظ أن Apple تطلب منك الحصول على موافقة صريحة من المستخدمين قبل ربط حسابات Apple الخاصة بهم ببيانات أخرى.

لن يسمح لك تسجيل الدخول مع Apple بإعادة استخدام بيانات اعتماد المصادقة للربط بحساب موجود. إذا كنت تريد ربط تسجيل الدخول باستخدام بيانات اعتماد Apple بحساب آخر ، فيجب عليك أولاً محاولة ربط الحسابات باستخدام تسجيل الدخول القديم ببيانات اعتماد Apple ثم فحص الخطأ الذي تم إرجاعه للعثور على بيانات اعتماد جديدة. سوف يكون موجودا الاعتماد جديد في خطأ في userInfo القاموس، ويمكن الوصول إليها عن طريق FIRAuthErrorUserInfoUpdatedCredentialKey مفتاح.

على سبيل المثال ، لربط حساب Facebook بحساب Firebase الحالي ، استخدم رمز الوصول الذي حصلت عليه من تسجيل دخول المستخدم إلى Facebook:

سويفت

// Initialize a Facebook credential with Firebase.
let credential = FacebookAuthProvider.credential(
  withAccessToken: AccessToken.current!.tokenString
)
// Assuming the current user is an Apple user linking a Facebook provider.
Auth.auth().currentUser.link(with: credential) { (authResult, error) in
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}

ج موضوعية

// Initialize a Facebook credential with Firebase.
FacebookAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken];
// Assuming the current user is an Apple user linking a Facebook provider.
[FIRAuth.auth linkWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}];

الخطوات التالية

بعد أن يقوم المستخدم بتسجيل الدخول لأول مرة ، يتم إنشاء حساب مستخدم جديد وربطه ببيانات الاعتماد - أي اسم المستخدم وكلمة المرور أو رقم الهاتف أو معلومات موفر المصادقة - المستخدم الذي قام بتسجيل الدخول باستخدام. يتم تخزين هذا الحساب الجديد كجزء من مشروع Firebase الخاص بك ، ويمكن استخدامه لتحديد هوية مستخدم عبر كل تطبيق في مشروعك ، بغض النظر عن كيفية تسجيل المستخدم للدخول.

  • في التطبيقات الخاصة بك، يمكنك الحصول على المعلومات الشخصية الأساسية للمستخدم من FIRUser الكائن. انظر إدارة المستخدمين .

  • في قاعدة البيانات الخاصة بك Firebase الحقيقي وسحابة التخزين قواعد الأمن ، يمكنك الحصول على قعت في هوية المستخدم الفريد المستخدم من auth متغير، واستخدامها للسيطرة على ما هي البيانات على وصول ويمكن للمستخدم.

يمكنك السماح للمستخدمين تسجيل الدخول إلى التطبيق الخاص بك باستخدام موفري المصادقة متعددة عن طريق ربط المصادقة أوراق اعتماد مقدم إلى حساب مستخدم موجود.

تسجيل الخروج مستخدم، استدعاء signOut: .

سويفت

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

ج موضوعية

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

قد ترغب أيضًا في إضافة رمز معالجة الأخطاء للنطاق الكامل من أخطاء المصادقة. نرى أخطاء مقبض .