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

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

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

قبل البدء

  1. فعِّل موفِّرًا واحدًا على الأقل يتيح ميزة "التحقّق من الهوية في عدة مراحل". يُرجى العلم أنّ جميع مقدّمي الخدمة سوى مقدّمي الخدمة التاليين يتيحون ميزة "التحقّق من الهوية الإضافي":

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

  3. ثبِّت حزمة تطوير البرامج (SDK) لمنصّة Android من Firebase إذا لم يسبق لك إجراء ذلك.

    لا تتوفّر ميزة "التوثيق المتعدّد العوامل باستخدام مصادقة كلمة مرور صالحة لمرة واحدة" إلا على الإصدار 22.1.0 من حزمة تطوير البرامج (SDK) لنظام Android والإصدارات الأحدث.

تفعيل المصادقة المتعدّدة العوامل باستخدام رمز مصادقة الوقت المتغيّر (TOTP)

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

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

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

    لا يتوافق TOTP MFA إلّا مع الإصدار 11.6.0 والإصدارات الأحدث من حزمة تطوير البرامج (SDK) لمشرف Firebase.

  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: عدد فواصل الإطار الزمني، من صفر إلى عشرة والإعداد الافتراضي هو خمسة.

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

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

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

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

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

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

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

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

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

  1. أعِد مصادقة المستخدم.

  2. إنشاء مفتاح TOTP سرّي للمستخدم الذي تمت مصادقته:

    // Generate a TOTP secret.
    Firebase.auth.currentUser.multiFactor.session
        .addOnSuccessListener { multiFactorSession ->
            TotpMultiFactorGenerator.generateSecret(multiFactorSession)
                .addOnSuccessListener { totpSecret ->
                    // Display the secret to the user and prompt them to
                    // enter it into their authenticator app. (See the next
                    // step.)
                }
        }
    
  3. اعرض السر على المستخدم واطلب منه إدخاله في تطبيق المصادقة:

    // Display this key:
    val secret = totpSecret.sharedSecretKey
    

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

    val qrCodeUri = totpSecret.generateQrCodeUrl(
        currentUser.email ?: "default account",
        "Your App Name")
    totpSecret.openInOtpApp(qrCodeUri)
    

    بعد أن يضيف المستخدم المفتاح السرّي إلى تطبيق المصادقة، سيبدأ إنشاء بروتوكولات TOTP.

  4. اطلب من المستخدم كتابة كلمة المرور لمرة واحدة (TOTP) التي يعرضها تطبيق المصادقة و استخدامها لإكمال عملية التسجيل في ميزة "التحقّق الإضافي":

    // Ask the user for a verification code from the authenticator app.
    val verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    val multiFactorAssertion = TotpMultiFactorGenerator
        .getAssertionForEnrollment(totpSecret, verificationCode)
    Firebase.auth.currentUser.multiFactor.enroll(multiFactorAssertion, "TOTP")
        .addOnSuccessListener {
            // Enrollment complete.
        }
    

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

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

  1. يمكنك استدعاء إحدى الطريقتين (signInWith) كما تفعل في حال عدم استخدام المواقع المصممة بغرض الإعلانات (MFA). (على سبيل المثال، signInWithEmailAndPassword().) إذا تسبّبت الطريقة في حدوث خطأ FirebaseAuthMultiFactorException، ابدأ عملية مصادقة متعدّدة العوامل في تطبيقك.

    Firebase.auth.signInWithEmailAndPassword(email, password)
        .addOnSuccessListener { result ->
            // 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.)
    
            // ...
        }
        .addOnFailureListener { exception ->
            when (exception) {
                is FirebaseAuthMultiFactorException -> {
                    // Initiate your second factor sign-in flow. (See next step.)
                    // ...
                }
            }
        }
    
  2. يجب أن يحث تدفق MFA في تطبيقك أولاً المستخدم على اختيار العامل الثاني الذي يريد استخدامه. يمكنك الحصول على قائمة بالعوامل الثانية المتوافقة من خلال فحص سمة hints مثيل MultiFactorResolver:

    val enrolledFactors = exception.resolver.hints.map { it.displayName }
    
  3. إذا اختار المستخدم استخدام TOTP، اطلب منه كتابة تفاصيل TOTP المعروض على تطبيق المصادقة واستخدامها لتسجيل الدخول:

    when (exception.resolver.hints[selectedIndex].factorId) {
        TotpMultiFactorGenerator.FACTOR_ID -> {
            val otpFromAuthenticator = // OTP typed by the user.
            val assertion = TotpMultiFactorGenerator.getAssertionForSignIn(
                exception.resolver.hints[selectedIndex].uid,
                otpFromAuthenticator
            )
            exception.resolver.resolveSignIn(assertion)
                .addOnSuccessListener { result ->
                    // Successfully signed in!
                }
                .addOnFailureListener { resolveError ->
                    // Invalid or expired OTP.
                }
        }
        PhoneMultiFactorGenerator.FACTOR_ID -> {
            // Handle SMS second factor.
        }
    }
    

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

يوضّح هذا القسم كيفية التعامل مع إلغاء تسجيل مستخدم من مصادقة العوامل المتعددة باستخدام رمز مفتاح المرور لمرة واحدة (TOTP).

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

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

Firebase.auth.currentUser.multiFactor.unenroll(mfaEnrollmentId)
    .addOnSuccessListener {
        // Second factor unenrolled.
    }
    .addOnFailureListener { exception ->
        when (exception) {
            is FirebaseAuthInvalidUserException -> {
                // Second factor unenrolled. 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.
                val credential = EmailAuthProvider.getCredential(email, password)
                currentUser.reauthenticate(credential)
                    .addOnSuccessListener { 
                        // Success!
                    }
                    .addOnFailureListener { 
                        // Bad email address and password combination.
                    }
            }
        }
    }

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