إضافة المصادقة المتعدّدة العوامل (TOTP) إلى تطبيق الويب

إذا كنت قد أجريت ترقية إلى الإصدار Firebase Authentication with Identity Platform، يمكنك إضافة المصادقة المتعدّدة العوامل (MFA) المستندة إلى كلمة المرور لمرة واحدة المستندة إلى الوقت (TOTP) إلى تطبيقك.

يتيح لك Firebase Authentication with Identity Platform استخدام TOTP كعامل إضافي لحساب MFA. عند تفعيل هذه الميزة، يظهر للمستخدمين الذين يحاولون تسجيل الدخول إلى تطبيقك طلب للحصول على رمز مرور متغيّر. ولإنشائها، يجب استخدام تطبيق مصادقة يمكنه إنشاء رموز TOTP صالحة، مثل Google Authenticator.

قبل البدء

  1. فعِّل موفِّرًا واحدًا على الأقل يتيح ميزة "التحقّق من الهوية في عدة مراحل". يُرجى العِلم أنّ جميع مقدّمي الخدمات باستثناء الجهات التالية التي تتوافق مع المواقع المصممة بغرض الإعلانات (MFA):

    • المصادقة عبر الهاتف
    • المصادقة المجهولة
    • رموز المصادقة المخصّصة
    • Apple Game Center
  2. تأكَّد من أنّ تطبيقك يتحقق من عناوين البريد الإلكتروني للمستخدمين. تتطلّب ميزة "التحقّق من الهوية في خطوتَين" إثبات ملكية عنوان البريد الإلكتروني. ويمنع ذلك الجهات الفاعلة الضارّة من التسجيل في خدمة باستخدام عنوان بريد إلكتروني لا يملكه، ثم حظر مالك عنوان البريد الإلكتروني الفعلي من خلال إضافة عامل ثانٍ.

  3. ثبِّت حزمة تطوير البرامج (SDK) لـ JavaScript في Firebase إذا لم يسبق لك ذلك.

    لا تتوفّر ميزة "التأكّد من الهوية باستخدام كلمة مرور متغيّرة في الوقت (TOTP)" إلا في حزمة Web SDK المكوّنة من وحدات، والإصدارات 9.19.1 والإصدارات الأحدث.

تفعيل TOTP MFA

لتفعيل بروتوكول TOTP كعامل ثانٍ، استخدِم Admin SDK أو اتصل بنقطة نهاية تنسيق REST لإعدادات المشروع.

لاستخدام Admin SDK، اتّبِع الخطوات التالية:

  1. ثبِّت حزمة تطوير البرامج (SDK) لواجهة Firebase Admin Node.js إذا لم يسبق لك إجراء ذلك.

    لا تتوفّر ميزة "التأكّد من الهوية باستخدام كلمة مرور صالحة لمرة واحدة" إلا في الإصدار 11.6.0 من حزمة تطوير برامج (SDK) Firebase Admin Node.js والإصدارات الأحدث.

  2. قم بتشغيل ما يلي:

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: NUM_ADJ_INTERVALS
                  }
              }]
          }
    })
    

    استبدِل ما يلي:

    • NUM_ADJ_INTERVALS: عدد فواصل المَعلمة time-window المجاورة التي يتم من خلالها قبول الرموز المميّزة لوقت التشغيل (TOTP)، من صفر إلى عشرة. الإعداد التلقائي هو خمسة.

      يعمل مورّدو وسائل النقل (TOTP) عن طريق التأكّد من أنّه عندما ينشئ طرفان (المثبت والمدقق) كلمات المرور لمرة واحدة (OTP) خلال الفترة الزمنية نفسها (التي تبلغ مدتها عادةً 30 ثانية)، ينشئان كلمة المرور نفسها. ومع ذلك، لتلبية اختلاف التوقيت بين الطرفَين ووقت استجابة المستخدم، يمكنك ضبط خدمة TOTP لقبول الرموز من النوافذ المجاورة أيضًا.

لتفعيل المصادقة المتعدّدة العوامل باستخدام رمز مرور متغيّر الوقت (TOTP) باستخدام واجهة برمجة التطبيقات REST، نفِّذ ما يلي:

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": NUM_ADJ_INTERVALS
            }
          }]
       }
    }'

استبدِل ما يلي:

  • PROJECT_ID: رقم تعريف المشروع
  • NUM_ADJ_INTERVALS: عدد فواصل الإطار الزمني، من صفر إلى عشرة والإعداد الافتراضي هو خمسة.

    يعمل مورّدو وسائل النقل (TOTP) عن طريق التأكّد من أنّه عندما ينشئ طرفان (المثبت والمدقق) كلمات المرور لمرة واحدة (OTP) خلال الفترة الزمنية نفسها (التي تبلغ مدتها عادةً 30 ثانية)، ينشئان كلمة المرور نفسها. ومع ذلك، لتلبية اختلاف التوقيت بين الطرفَين ووقت استجابة المستخدم، يمكنك ضبط خدمة TOTP لقبول الرموز من النوافذ المجاورة أيضًا.

اختيار نمط التسجيل

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

  • سجِّل العامل الثاني للمستخدِم كجزء من عملية التسجيل. استخدِم هذه الطريقة إذا كان تطبيقك يتطلّب مصادقة متعددة العوامل لجميع المستخدمين.

  • عليك توفير خيار قابل للتخطّي لتسجيل عامل ثانٍ أثناء التسجيل. إذا أردت تشجيع استخدام المصادقة المتعدّدة العوامل في تطبيقك بدون فرضها، يمكنك استخدام هذا النهج.

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

  • اشترِط إضافة عامل ثانٍ بشكل تدريجي عندما يريد المستخدم الوصول إلى الميزات التي تتطلب متطلبات أمان متزايدة.

تسجيل المستخدمين في TOTP MFA

بعد تفعيل TOTP MFA كعامل ثانٍ لتطبيقك، عليك تنفيذ منطق من جهة العميل لتسجيل المستخدمين في TOTP MFA:

  1. استورِد فئات وظائف المصادقة المتعددة العوامل المطلوبة:

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. أعِد مصادقة المستخدم.

  3. أنشئ سرًا لبروتوكول TOTP للمستخدم الذي تمّت مصادقة هويته:

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. عرض السرّ على المستخدم وطلب إدخاله في تطبيق المصادقة

    باستخدام العديد من تطبيقات المصادقة، يمكن للمستخدمين إضافة أسرار جديدة لبروتوكول TOTP بسرعة من خلال مسح رمز استجابة سريعة ضوئيًا يمثّل عنوان URL لمفتاح متوافق مع Google Authenticator. ولإنشاء رمز استجابة سريعة لهذا الغرض، يمكنك إنشاء عنوان URI باستخدام generateQrCodeUrl() ثم ترميزه باستخدام مكتبة رموز الاستجابة السريعة من اختيارك. على سبيل المثال:

    const totpUri = totpSecret.generateQrCodeUrl(
        currentUser.email,
        "Your App's Name"
    );
    await QRExampleLib.toCanvas(totpUri, qrElement);
    

    بغض النظر عما إذا كنت تعرض رمز الاستجابة السريعة، احرص دائمًا على عرض المفتاح السري لإتاحة تطبيقات المصادقة التي لا يمكنها قراءة رموز الاستجابة السريعة:

    // Also display this key:
    const secret = totpSecret.secretKey;
    

    بعد أن يضيف المستخدم مفتاحه السري إلى تطبيق المصادقة، سيبدأ التطبيق في توليد رمز OTP.

  5. اطلب من المستخدم كتابة تفاصيل TOTP المعروض على تطبيق المصادقة واستخدامه لإنهاء التسجيل في MFA:

    // Ask the user for a verification code from the authenticator app.
    const verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
      totpSecret,
      verificationCode
    );
    await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
    

تسجيل دخول المستخدمين بعامل ثانٍ

لتسجيل دخول المستخدمين باستخدام المصادقة المتعدّدة العوامل من خلال رمز مرور متغيّر (TOTP)، استخدِم الرمز التالي:

  1. استورِد فئات وظائف المصادقة المتعددة العوامل المطلوبة:

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. يمكنك استدعاء إحدى الطريقتين (signInWith) كما تفعل في حال عدم استخدام المواقع المصممة بغرض الإعلانات (MFA). (على سبيل المثال، signInWithEmailAndPassword().) إذا ظهرت رسالة خطأ auth/multi-factor-auth-required، ابدأ عملية مصادقة ثنائية العوامل في تطبيقك.

    try {
        const userCredential = await signInWithEmailAndPassword(
            getAuth(),
            email,
            password
        );
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch (error) {
        switch (error.code) {
            case "auth/multi-factor-auth-required":
                // Initiate your second factor sign-in flow. (See next step.)
                // ...
                break;
            case ...:  // Handle other errors, such as wrong passwords.
                break;
        }
    }
    
  3. يجب أن يطلب مسار المصادقة المتعددة العوامل في تطبيقك من المستخدم أولاً اختيار العامل الثاني الذي يريد استخدامه. يمكنك الحصول على قائمة بالعوامل الثانية المتوافقة من خلال فحص سمة hints مثيل MultiFactorResolver:

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. إذا اختار المستخدم استخدام كلمة المرور لمرة واحدة (TOTP)، اطلب منه كتابة كلمة المرور لمرة واحدة (TOTP) المعروضة على تطبيق المصادقة واستخدامها لتسجيل الدخول:

    switch (mfaResolver.hints[selectedIndex].factorId) {
        case TotpMultiFactorGenerator.FACTOR_ID:
            const otpFromAuthenticator = // OTP typed by the user.
            const multiFactorAssertion =
                TotpMultiFactorGenerator.assertionForSignIn(
                    mfaResolver.hints[selectedIndex].uid,
                    otpFromAuthenticator
                );
            try {
                const userCredential = await mfaResolver.resolveSignIn(
                    multiFactorAssertion
                );
                // Successfully signed in!
            } catch (error) {
                // Invalid or expired OTP.
            }
            break;
        case PhoneMultiFactorGenerator.FACTOR_ID:
            // Handle SMS second factor.
            break;
        default:
            // Unsupported second factor?
            break;
    }
    

إلغاء التسجيل في ميزة "التأكّد من الهوية باستخدام كلمة مرور صالحة لمرة واحدة" (TOTP)

يصف هذا القسم كيفية التعامل مع إلغاء تسجيل مستخدم في TOTP MFA.

إذا اشترك مستخدم في خيارات متعددة للمصادقة المتعددة العوامل، وفي حال إلغاء تسجيله من الخيار الذي تم تفعيله مؤخرًا، سيتلقّى auth/user-token-expired وسيتم تسجيل خروجه. على المستخدم تسجيل الدخول مرة أخرى وإثبات صحة بيانات الاعتماد الحالية، مثل عنوان البريد الإلكتروني وكلمة المرور.

لإلغاء تسجيل المستخدم ومعالجة الخطأ وبدء إعادة المصادقة، استخدِم الرمز التالي:

import {
    EmailAuthProvider,
    TotpMultiFactorGenerator,
    getAuth,
    multiFactor,
    reauthenticateWithCredential,
} from "firebase/auth";

try {
    // Unenroll from TOTP MFA.
    await multiFactor(currentUser).unenroll(mfaEnrollmentId);
} catch  (error) {
    if (error.code === 'auth/user-token-expired') {
        // If the user was signed out, re-authenticate them.

        // For example, if they signed in with a password, prompt them to
        // provide it again, then call `reauthenticateWithCredential()` as shown
        // below.

        const credential = EmailAuthProvider.credential(email, password);
        await reauthenticateWithCredential(
            currentUser,
            credential
        );
    }
}

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