المصادقة مع Firebase باستخدام رقم هاتف باستخدام JavaScript

يمكنك استخدام Firebase Authentication لتسجيل دخول مستخدم من خلال إرسال رسالة SMS إلى هاتفه. يسجّل المستخدم الدخول باستخدام رمز صالح لمرة واحدة وارد في رسالة SMS.

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

قبل البدء

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

المخاوف المرتبطة بالأمان

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

إذا كنت تستخدم ميزة تسجيل الدخول المستندة إلى رقم الهاتف في تطبيقك، عليك توفيرها إلى جانب طرق تسجيل دخول أكثر أمانًا، وإبلاغ المستخدمين بمزايا وعيوب استخدام ميزة تسجيل الدخول المستندة إلى رقم الهاتف.

تفعيل تسجيل الدخول باستخدام رقم الهاتف في مشروعك على Firebase

لتسجيل دخول المستخدمين باستخدام الرسائل القصيرة، يجب أولاً تفعيل طريقة تسجيل الدخول باستخدام رقم الهاتف لمشروعك على Firebase باتّباع الخطوات التالية:

  1. في وحدة تحكّم Firebase، افتح قسم المصادقة.
  2. في صفحة طريقة تسجيل الدخول، فعِّل طريقة تسجيل الدخول باستخدام رقم الهاتف.
  3. في صفحة الإعدادات، اضبط سياسة بشأن المناطق التي تريد السماح فيها بإرسال رسائل SMS أو حظر ذلك. بالنسبة إلى المشاريع الجديدة، لا تسمح السياسة التلقائية بأي مناطق.
  4. في الصفحة نفسها، إذا لم يكن النطاق الذي سيستضيف تطبيقك مدرَجًا في قسم نطاقات إعادة التوجيه في OAuth، أضِف نطاقك. يُرجى العِلم أنّه لا يُسمح باستخدام المضيف المحلي كنطاق مستضاف لأغراض مصادقة الهاتف.

إعداد أداة التحقّق reCAPTCHA

قبل أن تتمكّن من تسجيل دخول المستخدمين باستخدام أرقام هواتفهم، عليك إعداد أداة التحقّق reCAPTCHA من Firebase. تستخدم Firebase خدمة reCAPTCHA لمنع إساءة الاستخدام، مثلاً من خلال التأكّد من أنّ طلب تأكيد رقم الهاتف وارد من إحدى النطاقات المسموح بها في تطبيقك.

لست بحاجة إلى إعداد عميل reCAPTCHA يدويًا، فعند استخدام عنصر RecaptchaVerifier في حزمة تطوير البرامج (SDK) من Firebase، تنشئ Firebase تلقائيًا أي مفاتيح وأسرار ضرورية للعميل وتتعامل معها.

يتوافق العنصر RecaptchaVerifier مع invisible reCAPTCHA، التي يمكنها غالبًا التحقّق من المستخدم بدون الحاجة إلى أي إجراء من جانبه، بالإضافة إلى أداة reCAPTCHA المصغّرة التي تتطلّب دائمًا تفاعل المستخدم لإكمالها بنجاح.

يمكن ترجمة reCAPTCHA الأساسية المعروضة إلى اللغة المفضّلة لدى المستخدم من خلال تعديل رمز اللغة في مثيل Auth قبل عرض reCAPTCHA. سينطبق التكييف مع اللغات المذكورة أعلاه أيضًا على الرسالة القصيرة التي يتم إرسالها إلى المستخدم والتي تحتوي على رمز التحقّق.

Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

استخدام شارة reCAPTCHA غير المرئية

لاستخدام reCAPTCHA غير المرئية، أنشئ عنصر RecaptchaVerifier مع ضبط المَعلمة size على invisible، مع تحديد معرّف الزر الذي يرسل نموذج تسجيل الدخول. على سبيل المثال:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

استخدام أداة reCAPTCHA

لاستخدام أداة reCAPTCHA المرئية، أنشئ عنصرًا على صفحتك يحتوي على الأداة، ثم أنشئ عنصر RecaptchaVerifier، وحدِّد معرّف الحاوية عند إجراء ذلك، على سبيل المثال:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

اختياري: حدِّد مَعلمات reCAPTCHA

يمكنك اختياريًا ضبط دوال رد الاتصال على العنصر RecaptchaVerifier الذي يتم استدعاؤه عندما يحل المستخدم اختبار reCAPTCHA أو عندما تنتهي صلاحية reCAPTCHA قبل أن يرسل المستخدم النموذج:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

اختياري: العرض المُسبَق لـ reCAPTCHA

إذا أردت عرض reCAPTCHA مسبقًا قبل إرسال طلب تسجيل الدخول، استخدِم الرمز render:

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

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

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

إرسال رمز تأكيد إلى هاتف المستخدم

لبدء عملية تسجيل الدخول باستخدام رقم الهاتف، اعرض على المستخدم واجهة تطلب منه تقديم رقم هاتفه، ثم استدعِ signInWithPhoneNumber لطلب أن يرسل Firebase رمز مصادقة إلى هاتف المستخدم عبر الرسائل القصيرة:

  1. الحصول على رقم هاتف المستخدم

    تختلف المتطلبات القانونية، ولكن كأفضل ممارسة ولتحديد توقعات المستخدمين، عليك إعلامهم بأنّه في حال استخدام ميزة "تسجيل الدخول باستخدام الهاتف"، قد يتلقّون رسالة SMS لإثبات الملكية وسيتم تطبيق الأسعار العادية.

  2. استدعِ الدالة signInWithPhoneNumber، مع تمرير رقم هاتف المستخدم وRecaptchaVerifier الذي أنشأته سابقًا.

    Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    إذا أدّى signInWithPhoneNumber إلى حدوث خطأ، أعِد ضبط reCAPTCHA ليتمكّن المستخدم من المحاولة مرة أخرى:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });

تُصدر الطريقة signInWithPhoneNumber تحدّي reCAPTCHA للمستخدم، وإذا اجتاز المستخدم التحدّي، تطلب الطريقة Firebase Authentication إرسال رسالة SMS تحتوي على رمز التحقّق إلى هاتف المستخدم.

تسجيل دخول المستخدم باستخدام رمز التحقّق

بعد نجاح طلب signInWithPhoneNumber، اطلب من المستخدم كتابة رمز التحقّق الذي تلقّاه عبر الرسائل القصيرة. بعد ذلك، سجِّل دخول المستخدم من خلال تمرير الرمز إلى الطريقة confirm الخاصة بالعنصر ConfirmationResult الذي تم تمريره إلى معالج التنفيذ الخاص بـ signInWithPhoneNumber (أي الكتلة then). على سبيل المثال:

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

إذا نجحت عملية طلب confirm، يتم تسجيل دخول المستخدم بنجاح.

الحصول على عنصر AuthCredential الوسيط

إذا كنت بحاجة إلى الحصول على عنصر AuthCredential لحساب المستخدم، مرِّر رمز التحقّق من نتيجة التأكيد ورمز التحقّق إلى PhoneAuthProvider.credential بدلاً من استدعاء confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

بعد ذلك، يمكنك تسجيل دخول المستخدم باستخدام بيانات الاعتماد:

firebase.auth().signInWithCredential(credential);

الاختبار باستخدام أرقام هواتف وهمية

يمكنك إعداد أرقام هواتف وهمية لأغراض التطوير من خلال وحدة تحكّم Firebase. تقدّم الاختبارات باستخدام أرقام هواتف وهمية المزايا التالية:

  • اختبار مصادقة رقم الهاتف بدون استهلاك حصة الاستخدام
  • اختبار مصادقة رقم الهاتف بدون إرسال رسالة SMS فعلية
  • إجراء اختبارات متتالية باستخدام رقم الهاتف نفسه بدون أن يتم تقييد عددها يقلّل ذلك من خطر الرفض أثناء عملية مراجعة التطبيق في "متجر التطبيقات" إذا استخدم المراجع رقم الهاتف نفسه للاختبار.
  • إجراء الاختبارات بسهولة في بيئات التطوير بدون أي جهد إضافي، مثل إمكانية التطوير في محاكي iOS أو محاكي Android بدون "خدمات Google Play"
  • كتابة اختبارات الدمج بدون أن يتم حظرها من خلال عمليات التحقّق من الأمان التي يتم تطبيقها عادةً على أرقام الهواتف الحقيقية في بيئة الإنتاج

يجب أن تستوفي أرقام الهواتف الوهمية المتطلبات التالية:

  1. تأكَّد من استخدام أرقام هواتف وهمية بالفعل وغير مستخدَمة من قبل. لا تسمح لك Firebase Authentication بتحديد أرقام هواتف حالية يستخدمها مستخدمون حقيقيون كأرقام اختبارية. أحد الخيارات هو استخدام أرقام تبدأ بالرقم 555 كأرقام هواتف اختبارية في الولايات المتحدة، على سبيل المثال: +1 650-555-3434
  2. يجب أن تكون أرقام الهواتف منسَّقة بشكل صحيح من حيث الطول والقيود الأخرى. وستخضع هذه الأرقام لعملية التحقّق نفسها التي يخضع لها رقم الهاتف الخاص بالمستخدم الحقيقي.
  3. يمكنك إضافة ما يصل إلى 10 أرقام هواتف للتطوير.
  4. استخدِم أرقام هواتف/رموز اختبار يصعب تخمينها وتغييرها بشكل متكرر.

إنشاء أرقام هواتف ورموز تحقّق وهمية

  1. في وحدة تحكّم Firebase، افتح قسم المصادقة.
  2. في علامة التبويب طريقة تسجيل الدخول، فعِّل "مقدّم خدمة الهاتف" إذا لم يسبق لك إجراء ذلك.
  3. افتح قائمة الأكورديون أرقام الهواتف المخصّصة للاختبار.
  4. أدخِل رقم الهاتف الذي تريد اختباره، مثلاً: +1 650-555-3434.
  5. أدخِل رمز التحقّق المكوّن من 6 أرقام لهذا الرقم تحديدًا، مثلاً: 654321.
  6. أضِف الرقم. إذا دعت الحاجة، يمكنك حذف رقم الهاتف والرمز الخاص به من خلال تمرير مؤشر الماوس فوق الصف المعنيّ والنقر على رمز المهملات.

الاختبار اليدوي

يمكنك البدء مباشرةً في استخدام رقم هاتف وهمي في تطبيقك. يتيح لك ذلك إجراء اختبار يدوي خلال مراحل التطوير بدون مواجهة مشاكل في الحصة أو الحدّ من السرعة. يمكنك أيضًا إجراء الاختبار مباشرةً من محاكي iOS أو محاكي Android بدون تثبيت "خدمات Google Play".

عند تقديم رقم الهاتف الوهمي وإرسال رمز التحقّق، لن يتم إرسال أي رسالة SMS فعلية. بدلاً من ذلك، عليك تقديم رمز التحقّق الذي تم ضبطه سابقًا لإكمال عملية تسجيل الدخول.

عند اكتمال عملية تسجيل الدخول، يتم إنشاء مستخدم Firebase باستخدام رقم الهاتف هذا. يتصرف المستخدم ويملك الخصائص نفسها التي يملكها مستخدم رقم الهاتف الحقيقي، ويمكنه الوصول إلى Realtime Database/Cloud Firestore والخدمات الأخرى بالطريقة نفسها. يحتوي رمز التعريف المميز الذي تم إنشاؤه خلال هذه العملية على التوقيع نفسه الذي يستخدمه مستخدم رقم الهاتف الحقيقي.

هناك خيار آخر وهو ضبط دور اختباري من خلال المطالبات المخصّصة لهؤلاء المستخدمين لتصنيفهم كمستخدمين مزيفين إذا أردت فرض قيود إضافية على إمكانية الوصول.

اختبار التكامل

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

على الويب، اضبط قيمة appVerificationDisabledForTesting على true قبل عرض firebase.auth.RecaptchaVerifier. يؤدي ذلك إلى حلّ اختبار reCAPTCHA تلقائيًا، ما يتيح لك إدخال رقم الهاتف بدون حلّه يدويًا. يُرجى العِلم أنّه حتى في حال إيقاف reCAPTCHA، سيظلّ تعذُّر إكمال عملية تسجيل الدخول عند استخدام رقم هاتف غير وهمي. لا يمكن استخدام أرقام هواتف وهمية إلا مع واجهة برمجة التطبيقات هذه.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

تختلف طريقة عمل أدوات التحقّق من التطبيقات الوهمية المرئية وغير المرئية في reCAPTCHA عند إيقاف ميزة التحقّق من التطبيقات، وذلك على النحو التالي:

  • ‫Visible reCAPTCHA: عند عرض Visible reCAPTCHA من خلال appVerifier.render()، يتم حلّها تلقائيًا بعد تأخير بجزء من الثانية. هذا الإجراء مكافئ لنقر المستخدم على reCAPTCHA فور عرضها. ستنتهي صلاحية رد reCAPTCHA بعد فترة من الوقت، ثم سيتم حلّ المشكلة تلقائيًا مرة أخرى.
  • ‫reCAPTCHA غير المرئية: لا يتم حلّ اختبار reCAPTCHA غير المرئية تلقائيًا عند العرض، بل يتم ذلك عند إجراء عملية appVerifier.verify()أو عند النقر على رابط الزر الخاص باختبار reCAPTCHA بعد تأخير بسيط. وبالمثل، ستنتهي صلاحية الرد بعد فترة من الوقت، ولن يتم حلّ المشكلة تلقائيًا إلا بعد إجراء مكالمة appVerifier.verify() أو عند النقر مرة أخرى على رابط الزر الخاص بخدمة reCAPTCHA.

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

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

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

  • في تطبيقاتك، الطريقة المقترَحة لمعرفة حالة المصادقة للمستخدم هي ضبط مراقب على العنصر Auth. يمكنك بعد ذلك الحصول على معلومات الملف الشخصي الأساسية للمستخدم من الكائن User. راجِع مقالة إدارة المستخدمين.

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

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

لتسجيل خروج مستخدم، اتّصِل بالرقم signOut:

Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});