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

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

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

قبل البدء

  1. فعِّل موفّرًا واحدًا على الأقل يتيح استخدام المصادقة المتعدّدة العوامل. يُرجى العلم أنّ جميع مقدّمي الخدمة باستثناء ما يلي يتيحون استخدام المصادقة المتعددة العوامل:

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

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

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

تفعيل المصادقة المتعددة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة

لتفعيل 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: عدد الفواصل الزمنية المتجاورة التي يمكن قبول رموز TOTP منها، ويتراوح بين صفر وعشرة. القيمة التلقائية هي خمسة.

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

لتفعيل المصادقة المتعددة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة باستخدام واجهة REST API، نفِّذ ما يلي:

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 من الفترات الزمنية المجاورة أيضًا.

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

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

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

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

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

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

تسجيل المستخدمين في المصادقة المتعدّدة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة (TOTP)

بعد تفعيل المصادقة المتعددة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة (TOTP) كعامل ثانٍ لتطبيقك، عليك تنفيذ منطق من جهة العميل لتسجيل المستخدمين في المصادقة المتعددة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة (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
    

    بالإضافة إلى عرض المفتاح السري، يمكنك محاولة إضافته تلقائيًا إلى تطبيق المصادقة التلقائي على الجهاز. ولإجراء ذلك، أنشئ معرّف موارد منتظم (URI) للمفتاح متوافقًا مع 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 كما لو كنت لا تستخدم المصادقة المتعددة العوامل. (على سبيل المثال، 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. يجب أن يطلب مسار المصادقة المتعدّدة العوامل في تطبيقك من المستخدم أولاً اختيار عامل المصادقة الثاني الذي يريد استخدامه. يمكنك الحصول على قائمة بالعوامل الثانوية المتوافقة من خلال فحص السمة 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.
        }
    }
    

إلغاء التسجيل في المصادقة المتعدّدة العوامل المستندة إلى كلمة المرور الصالحة لمرة واحدة

يوضّح هذا القسم كيفية التعامل مع مستخدم ألغى تسجيله في المصادقة المتعدّدة العوامل باستخدام كلمة المرور الصالحة لمرة واحدة.

إذا اشترك مستخدم في خيارات متعدّدة للمصادقة المتعددة العوامل، وألغى الاشتراك في الخيار الذي تم تفعيله مؤخرًا، سيتلقّى رسالة 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.
                    }
            }
        }
    }

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