المصادقة باستخدام Apple وC++

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

قبل البدء

لتسجيل دخول المستخدمين باستخدام حساب على Apple، عليك أولاً ضبط ميزة "تسجيل الدخول باستخدام حساب على Apple" على موقع المطوّرين الإلكتروني من Apple، ثم تفعيل Apple كموفِّر لتسجيل الدخول في مشروع Firebase.

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

لا يمكن ضبط ميزة "تسجيل الدخول باستخدام حساب على Apple" إلا من قِبل أعضاء برنامج Apple Developer Program.

ضبط ميزة "تسجيل الدخول باستخدام حساب على Apple"

يجب تفعيل ميزة "تسجيل الدخول باستخدام حساب على Apple" وضبطها بشكلٍ صحيح في مشروع Firebase. تختلف الإعدادات بين منصّتَي Android وApple. يُرجى اتّباع قسم "ضبط ميزة "تسجيل الدخول باستخدام حساب على Apple"" في أدلة منصّات Apple و/أو Android قبل المتابعة.

تفعيل Apple كموفِّر لتسجيل الدخول

  1. في وحدة تحكّم Firebase، انتقِل إلى الأمان > المصادقة.
  2. في علامة التبويب طريقة تسجيل الدخول ، فعِّل موفِّر تسجيل الدخول Apple.
  3. اضبط إعدادات موفِّر "تسجيل الدخول باستخدام حساب على Apple":
    • Apple: إذا كنت تنشر تطبيقك على منصّات Apple فقط، يمكنك ترك حقول "معرّف الخدمة" و"معرّف فريق Apple" و"المفتاح الخاص" و"معرّف المفتاح" فارغة.
    • Android: أكمل ما يلي لدعم أجهزة Android:
      1. كيفية إضافة Firebase إلى مشروع Android.
      2. حدِّد الملف المرجعي SHA-1 لتطبيقك إذا لم يسبق لك إجراء ذلك.
        1. في وحدة تحكّم Firebase، انتقِل إلى الإعدادات > علامة التبويب عام.
        2. انتقِل للأسفل إلى بطاقة تطبيقاتك، واختَر تطبيق Android، وأضِف الملف المرجعي SHA-1 في حقل الملفات المرجعية لشهادة SHA.

        يمكنك الاطّلاع على مقالة المصادقة على العميل للحصول على تفاصيل حول كيفية الحصول على الملف المرجعي SHA لتطبيقك.

      3. اضبط إعدادات موفِّر "تسجيل الدخول باستخدام حساب على Apple":
        1. في وحدة تحكّم Firebase، انتقِل إلى الأمان > المصادقة.
        2. في علامة التبويب طريقة تسجيل الدخول ، انقر على موفِّر تسجيل الدخول Apple.
        3. حدِّد معرّف الخدمة الذي أنشأته في القسم السابق. في قسم إعدادات عملية الحصول على رمز OAuth، حدِّد أيضًا معرّف فريق Apple والمفتاح الخاص ومعرّف المفتاح اللذين أنشأتهما في القسم السابق.

الامتثال لمتطلبات Apple بشأن البيانات المخفية الهوية

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

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

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

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

الوصول إلى الفئة firebase::auth::Auth

الفئة Auth هي البوابة لجميع طلبات البيانات من واجهة برمجة التطبيقات.
  1. أضِف ملفَي رأس Auth وApp:
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. في رمز التهيئة، أنشِئ فئة firebase::App.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
  3. احصل على الفئة firebase::auth::Auth لفئة firebase::App. هناك علاقة تطابق بين App وAuth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

التعامل مع عملية تسجيل الدخول باستخدام حزمة تطوير البرامج (SDK) لمنصّة Firebase

تختلف عملية "تسجيل الدخول باستخدام حساب على Apple" بين منصّتَي Apple وAndroid.

على منصّات Apple

يمكنك مصادقة المستخدمين باستخدام Firebase من خلال حزمة تطوير البرامج (SDK) لـ Apple Sign In Objective-C التي يتم استدعاؤها من رمز C++.

  1. لكل طلب تسجيل دخول، أنشِئ سلسلة عشوائية، وهي "رقم خاص"، ستستخدمها للتأكّد من أنّ رمز التعريف الذي تحصل عليه تم منحه استجابةً لطلب المصادقة الخاص بتطبيقك تحديدًا. هذه الخطوة مهمة لمنع هجمات إعادة التشغيل.

      - (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--;
            }
          }
        }
      }
    
    

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

  2. ابدأ عملية تسجيل الدخول من Apple، بما في ذلك تجزئة SHA256 للقيمة العشوائية وفئة المفوّض التي ستتعامل مع ردّ Apple (راجِع الخطوة التالية):

      - (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];
      }
    
      - (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. تعامَل مع ردّ Apple في عملية تنفيذ `ASAuthorizationControllerDelegate`. إذا تم تسجيل الدخول بنجاح، استخدِم الرمز المميّز للمعرّف من ردّ Apple مع القيمة العشوائية غير المجزّأة للمصادقة باستخدام Firebase:

      - (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);
          }
        }
    
  4. استخدِم سلسلة الرمز المميز الناتجة والقيمة العشوائية الأصلية لإنشاء بيانات اعتماد Firebase وتسجيل الدخول إلى Firebase.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. يمكن استخدام النمط نفسه مع Reauthenticate الذي يمكن استخدامه لاسترداد بيانات اعتماد جديدة للعمليات الحساسة التي تتطلب تسجيل الدخول مؤخرًا.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. يمكن استخدام النمط نفسه لربط حساب بميزة "تسجيل الدخول باستخدام حساب على Apple". ومع ذلك، قد يظهر لك خطأ عندما يكون حساب حالي على Firebase قد تم ربطه بحساب Apple الذي تحاول ربطه. عند حدوث ذلك، ستعرض النتيجة المستقبلية الحالة kAuthErrorCredentialAlreadyInUse وقد يحتوي AuthResult على credential صالحة. يمكن استخدام بيانات الاعتماد هذه لتسجيل الدخول إلى الحساب المرتبط بـ Apple من خلال SignInAndRetrieveDataWithCredential بدون الحاجة إلى إنشاء رمز مميز وقيمة عشوائية آخرَين لميزة "تسجيل الدخول باستخدام حساب على Apple".

    firebase::Future<firebase::auth::AuthResult> link_result =
        auth->current_user().LinkWithCredential(credential);
    
    // To keep example simple, wait on the current thread until call completes.
    while (link_result.status() == firebase::kFutureStatusPending) {
      Wait(100);
    }
    
    // Determine the result of the link attempt
    if (link_result.error() == firebase::auth::kAuthErrorNone) {
      // user linked correctly.
    } else if (link_result.error() ==
                   firebase::auth::kAuthErrorCredentialAlreadyInUse &&
               link_result.result()
                   ->additional_user_info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::AuthResult> result =
          auth->SignInAndRetrieveDataWithCredential(
              link_result.result()->additional_user_info.updated_credential);
    } else {
      // Another link error occurred.
    }

على Android

على Android، يمكنك مصادقة المستخدمين باستخدام Firebase من خلال دمج عملية تسجيل الدخول العامة المستندة إلى الويب باستخدام بروتوكول OAuth في تطبيقك باستخدام حزمة تطوير البرامج (SDK) لمنصّة Firebase لتنفيذ عملية تسجيل الدخول الكاملة.

للتعامل مع عملية تسجيل الدخول باستخدام حزمة تطوير البرامج (SDK) لمنصّة Firebase، اتّبِع الخطوات التالية:

  1. أنشِئ مثيلاً من FederatedOAuthProviderData تم ضبطه باستخدام معرّف المزوّد المناسب لـ Apple.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. اختياري: حدِّد نطاقات OAuth 2.0 إضافية بخلاف النطاقات التلقائية التي تريد طلبها من موفِّر المصادقة.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. اختياري: إذا كنت تريد عرض شاشة تسجيل الدخول من Apple بلغة أخرى غير الإنجليزية، اضبط المَعلمة locale. راجِع مستندات ميزة "تسجيل الدخول باستخدام حساب على Apple" للتعرّف على اللغات المتاحة.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. بعد ضبط بيانات المزوّد، استخدِمها لإنشاء FederatedOAuthProvider.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. يمكنك المصادقة باستخدام Firebase باستخدام عنصر موفِّر المصادقة. يُرجى العِلم أنّه على عكس عمليات FirebaseAuth الأخرى، سيتحكّم هذا الإجراء في واجهة المستخدم من خلال عرض طريقة عرض ويب يمكن للمستخدم إدخال بيانات اعتماده فيها.

    لبدء عملية تسجيل الدخول، استخدِم signInWithProvider:

    firebase::Future<firebase::auth::AuthResult> result =
      auth->SignInWithProvider(provider_data);
    

    يمكن لتطبيقك الانتظار أو تسجيل معاودة الاتصال في Future.

  6. يمكن استخدام النمط نفسه مع ReauthenticateWithProvider الذي يمكن استخدامه لاسترداد بيانات اعتماد جديدة للعمليات الحساسة التي تتطلب تسجيل الدخول مؤخرًا.

    firebase::Future<firebase::auth::AuthResult> result =
      user.ReauthenticateWithProvider(provider_data);
    

    يمكن لتطبيقك الانتظار أو تسجيل معاودة الاتصال في Future.

  7. يمكنك استخدام LinkWithCredential() لربط موفِّري الهوية المختلفين بالحسابات الحالية.

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

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

    // Initialize a Facebook credential with a Facebook access token.
    AuthCredential credential =
        firebase::auth::FacebookAuthProvider.getCredential(token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    firebase::Future<firebase::auth::AuthResult> result =
        auth.current_user().LinkWithCredential(credential);
    

ملاحظات حول ميزة "تسجيل الدخول باستخدام حساب على Apple"

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

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

لا يشارك Apple معلومات المستخدم، مثل اسم العرض، مع التطبيقات إلا في المرة الأولى التي يسجّل فيها المستخدم الدخول. عادةً، يخزّن Firebase اسم العرض في المرة الأولى التي يسجّل فيها المستخدم الدخول باستخدام حساب على Apple، ويمكنك الحصول عليه باستخدام current_user().display_name(). ومع ذلك، إذا سبق لك استخدام Apple لتسجيل دخول مستخدم إلى التطبيق بدون استخدام Firebase، لن يقدّم Apple اسم العرض للمستخدم إلى Firebase.

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

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

في تطبيقاتك، يمكنك الحصول على معلومات الملف الشخصي الأساسية للمستخدم من عنصر firebase::auth::User. راجِع مقالة إدارة المستخدمين.

في "قواعد الأمان" في قاعدة بيانات Firebase في الوقت الفعلي وCloud Storage، يمكنك الحصول على رقم تعريف المستخدم الفريد للمستخدم الذي سجّل الدخول من متغيّر المصادقة، واستخدامه للتحكّم في البيانات التي يمكن للمستخدم الوصول إليها.