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

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

قبل البدء

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

الانضمام إلى "برنامج المطوّرين من Apple"

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

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

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

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

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

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

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

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

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

يُرجى العِلم أنّ القائمة أعلاه ليست شاملة. يُرجى الرجوع إلى اتفاقية ترخيص برنامج Apple للمطوّرين في قسم "الاشتراك" ضمن حساب المطوّر للتأكّد من أنّ تطبيقك يستوفي متطلبات 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) بلغة Objective-C الخاصة بخدمة Apple Sign In، والتي يتم استدعاؤها من رمز 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 Credential وتسجيل الدخول إلى 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. راجِع مستندات &quot;تسجيل الدخول باستخدام Apple&quot; لمعرفة اللغات المتوافقة.

    // 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 Realtime Database وCloud Storage، يمكنك الحصول على معرّف المستخدم الفريد للمستخدم الذي سجّل الدخول من متغيّر المصادقة، واستخدامه للتحكّم في البيانات التي يمكن للمستخدم الوصول إليها.