المصادقة مع Firebase باستخدام حسابات مستندة إلى كلمة المرور باستخدام C++

يمكنك استخدام Firebase Authentication للسماح للمستخدمين بالمصادقة باستخدام Firebase باستخدام عناوين بريدهم الإلكتروني وكلمات مرورهم، وإدارة حسابات تطبيقك المستندة إلى كلمة المرور.

قبل البدء

  1. أضِف Firebase إلى مشروع C++.
  2. إذا لم يسبق لك ربط تطبيقك بمشروعك على Firebase، يمكنك إجراء ذلك من وحدة تحكّم Firebase.
  3. تفعيل تسجيل الدخول باستخدام عنوان البريد الإلكتروني أو كلمة المرور:
    1. في وحدة تحكّم Firebase، افتح قسم Auth.
    2. في علامة التبويب طريقة تسجيل الدخول، فعِّل طريقة تسجيل الدخول باستخدام البريد الإلكتروني/كلمة المرور وانقر على حفظ.

الوصول إلى الصف 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);

إنشاء حساب مستند إلى كلمة مرور

لإنشاء حساب مستخدم جديد باستخدام كلمة مرور، أكمِل الخطوات التالية في رمز تسجيل الدخول إلى تطبيقك:

  1. عندما يسجّل مستخدم جديد الدخول باستخدام نموذج الاشتراك في تطبيقك، أكمِل أي خطوات جديدة لفحص صحة حسابه يتطلّبها تطبيقك، مثل التحقّق من أنّه تمت كتابة كلمة مرور الحساب الجديد بشكل صحيح وتستوفي متطلبات الصعوبة .
  2. إنشاء حساب جديد من خلال تمرير عنوان البريد الإلكتروني وكلمة المرور للمستخدم الجديد إلى Auth::CreateUserWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPassword(email, password);
  3. إذا كان برنامجك يتضمّن حلقة تحديث يتم تشغيلها بانتظام (مثلاً 30 أو 60 مرة في الثانية)، يمكنك التحقّق من النتائج مرة واحدة لكل تحديث باستخدام Auth::CreateUserWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Create user succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Created user failed with error '%s'\n", result.error_message());
      }
    }
    أو إذا كان برنامجك مستندًا إلى الأحداث، يمكنك أن تفضّل تسجيل طلب معاودة الاتصال في المستقبل.

تسجيل دخول مستخدم باستخدام عنوان بريد إلكتروني وكلمة مرور

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

  1. عندما يسجّل مستخدم الدخول إلى تطبيقك، عليك إرسال عنوان البريد الإلكتروني للمستخدم وكلمة المرور إلى firebase::auth::Auth::SignInWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPassword(email, password);
  2. إذا كان برنامجك يتضمّن تكرارًا للتحديث يتم تشغيله بشكل منتظم (مثلاً 30 أو 60 مرة في الثانية)، يمكنك الاطّلاع على النتائج مرة واحدة لكل تحديث باستخدام Auth::SignInWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Sign in succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }
    أو إذا كان برنامجك مستندًا إلى الأحداث، قد تفضّل تسجيل طلب معاودة الاتصال في المستقبل.

تسجيل معاودة الاتصال في المستقبل

تحتوي بعض البرامج على دوال Update اسمها 30 أو 60 مرة في الثانية الواحدة. على سبيل المثال، تتّبع العديد من الألعاب هذا النموذج. يمكن لهذه البرامج استدعاء دوال LastResult لاستطلاع المكالمات غير المتزامنة. ومع ذلك، إذا كان برنامجك مستندًا إلى الأحداث، قد تفضّل تسجيل وظائف طلب معاودة الاتصال. يتم استدعاء دالة ردّ اتصال عند اكتمال Future.
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
يمكن أن تكون دالة "إعادة الاتصال" أيضًا دالة lambda، إذا كنت تفضّل ذلك.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

إجراء مقترَح: ضبط سياسة كلمة المرور

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

لضبط سياسة كلمات المرور لمشروعك، افتح علامة التبويب سياسة كلمة المرور في صفحة "إعدادات المصادقة" في وحدة تحكّم Firebase:

إعدادات المصادقة

تتيح Firebase Authentication سياسات كلمة المرور متطلبات كلمة المرور التالية:

  • يجب إدخال حرف صغير.

  • يجب إدخال حرف كبير.

  • يجب إدخال حرف رقمي.

  • يجب إدخال حرف غير أبجدي رقمي.

    تستوفي الأحرف التالية متطلبات الأحرف بخلاف الأحرف الأبجدية الرقمية: ^ $ * . [ ] { } ( ) ? " ! @ # % & / \ , > < ' : ; | _ ~

  • الحد الأدنى لطول كلمة المرور (يتراوح من 6 إلى 30 حرفًا، والإعداد التلقائي هو 6)

  • الحد الأقصى لطول كلمة المرور (الحد الأقصى هو 4096 حرفًا)

يمكنك تفعيل فرض سياسة كلمات المرور بطريقتَين:

  • طلب: تفشل محاولات الاشتراك إلى أن يغيّر المستخدم كلمة المرور لتكون متوافقة مع سياستك.

  • الإشعار: يُسمح للمستخدمين بالاشتراك باستخدام كلمة مرور غير متوافقة. عند استخدام هذا الوضع، يجب التحقّق مما إذا كانت كلمة مرور المستخدم تمتثل للسياسة من جهة العميل وطلب تعديل كلمة المرور من العميل بطريقة ما إذا لم تكن تمتثل.

على المستخدمين الجدد دائمًا اختيار كلمة مرور تتوافق مع سياستك.

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

إجراء ننصح به: تفعيل ميزة "الحماية من إدراج عناوين البريد الإلكتروني"

تُظهر بعض طرق Firebase Authentication التي تأخذ عناوين البريد الإلكتروني كمَعلمات أخطاء محدّدة إذا كان عنوان البريد الإلكتروني غير مسجَّل عندما يجب أن يكون مسجَّلاً (على سبيل المثال، عند تسجيل الدخول باستخدام عنوان بريد إلكتروني وكلمة مرور)، أو مسجَّلاً عندما يجب أن يكون غير مستخدَم (على سبيل المثال، عند تغيير عنوان البريد الإلكتروني الخاص بالمستخدم). على الرغم من أنّ ذلك قد يكون مفيدًا لاقتراح حلول محدّدة للمستخدمين، يمكن أن يتم أيضًا إساءة استخدامه من قِبل الجهات الضارّة لاكتشاف عناوين البريد الإلكتروني المسجّلة من قِبل مستخدميك.

للحدّ من هذا الخطر، ننصحك بتفعيل حماية تعداد البريد الإلكتروني لمشروعك باستخدام أداة gcloud في Google Cloud. يُرجى العِلم أنّ تفعيل هذه الميزة يؤدي إلى تغيير سلوك Firebase Authentication في الإبلاغ عن الأخطاء: تأكّد من أنّ تطبيقك لا يعتمد على الأخطاء الأكثر تحديدًا.

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

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

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

    firebase::auth::User user = auth->current_user();
    if (user.is_valid()) {
      std::string name = user.display_name();
      std::string email = user.email();
      std::string photo_url = user.photo_url();
      // The user's ID, unique to the Firebase project.
      // Do NOT use this value to authenticate with your backend server,
      // if you have one. Use firebase::auth::User::Token() instead.
      std::string uid = user.uid();
    }
  • في Firebase Realtime Database وCloud Storage قواعد الأمان، يمكنك الحصول على معرّف المستخدم الفريد للمستخدم الذي سجّل الدخول من متغيّر auth، واستخدامه للتحكّم في البيانات التي يمكن للمستخدم الوصول إليها.

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

لتسجيل خروج مستخدم، يمكنك الاتصال بالرقم SignOut():

auth->SignOut();