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

إذا تمت الترقية إلى مصادقة Firebase باستخدام "نظام أساسي للهوية"، يمكنك إضافة مصادقة متعدّدة العوامل للرسائل القصيرة SMS إلى تطبيق Flutter.

تزيد المصادقة المتعدّدة العوامل (MFA) من أمان تطبيقك. وعلى الرغم من أنّ المهاجمين يعرّضون غالبًا كلمات المرور والحسابات على وسائل التواصل الاجتماعي للخطر، يكون اعتراض الرسائل النصية أكثر صعوبةً.

قبل البدء

  1. فعِّل موفّر خدمة واحدًا على الأقل يتيح المصادقة المتعدّدة العوامل. يتيح كل مقدّم خدمة المصادقة المتعدّدة القنوات (MFA)، باستثناء مصادقة الهاتف، والمصادقة المجهولة، وApple Game Center.

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

  3. Android: إذا لم يسبق لك ضبط تجزئة SHA-256 لتطبيقك في وحدة تحكُّم Firebase، يُرجى إجراء ذلك. يمكنك مراجعة Authenticating Your Client للحصول على معلومات حول العثور على تجزئة SHA-256 لتطبيقك.

  4. iOS: في Xcode، يمكنك تفعيل الإشعارات الفورية لمشروعك والتأكُّد من ضبط مفتاح مصادقة أسماء نقاط الوصول (APNs) مع المراسلة عبر السحابة الإلكترونية من Firebase. بالإضافة إلى ذلك، يجب تفعيل أوضاع الخلفية للإشعارات عن بُعد. للاطّلاع على شرح تفصيلي لهذه الخطوة، يمكنك الاطّلاع على مستندات مصادقة الهاتف بنظام التشغيل iOS من Firebase.

  5. الويب: تأكَّد من إضافة نطاق تطبيقاتك إلى وحدة تحكُّم Firebase ضمن نطاقات إعادة توجيه OAuth.

تفعيل المصادقة المتعدّدة العوامل

  1. افتح صفحة المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase.

  2. في القسم الإعدادات المتقدّمة، فعِّل المصادقة المتعدّدة العوامل للرسائل القصيرة.

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

  3. إذا لم تكن قد فوّضت نطاق تطبيقك من قبل، يمكنك إضافته إلى قائمة السماح في صفحة المصادقة > الإعدادات بوحدة تحكُّم Firebase.

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

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

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

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

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

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

تسجيل عامل ثانٍ

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

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

  2. اطلب من المستخدم إدخال رقم هاتفه.

  3. الحصول على جلسة متعددة العوامل للمستخدم:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. يمكنك إثبات ملكية رقم الهاتف من خلال جلسة متعددة العوامل وعمليات معاودة الاتصال:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: multiFactorSession,
      phoneNumber: phoneNumber,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // The SMS verification code has been sent to the provided phone number.
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    ); 
    
  5. بعد إرسال رمز SMS، اطلب من المستخدم إثبات صحة الرمز باتّباع الخطوات التالية:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. أكمِل عملية التسجيل:

    await user.multiFactor.enroll(
      PhoneMultiFactorGenerator.getAssertion(
        credential,
      ),
    );
    

يوضح الرمز أدناه مثالاً كاملاً لتسجيل عامل ثانٍ:

  final session = await user.multiFactor.getSession();
  final auth = FirebaseAuth.instance;
  await auth.verifyPhoneNumber(
    multiFactorSession: session,
    phoneNumber: phoneController.text,
    verificationCompleted: (_) {},
    verificationFailed: (_) {},
    codeSent: (String verificationId, int? resendToken) async {
      // See `firebase_auth` example app for a method of retrieving user's sms code: 
      // https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
      final smsCode = await getSmsCodeFromUser(context);

      if (smsCode != null) {
        // Create a PhoneAuthCredential with the code
        final credential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: smsCode,
        );

        try {
          await user.multiFactor.enroll(
            PhoneMultiFactorGenerator.getAssertion(
              credential,
            ),
          );
        } on FirebaseAuthException catch (e) {
          print(e.message);
        }
      }
    },
    codeAutoRetrievalTimeout: (_) {},
  );

تهانينا لقد سجّلت بنجاح عامل مصادقة ثانٍ لمستخدم.

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

لتسجيل دخول مستخدم باستخدام ميزة إثبات الهوية عبر الرسائل القصيرة SMS:

  1. سجِّل دخول المستخدم باستخدام العامل الأول، ثم انقر على استثناء FirebaseAuthMultiFactorException. يتضمّن هذا الخطأ أداة حل يمكنك استخدامها للحصول على العوامل الثانية المسجَّلة للمستخدم. كما تحتوي على جلسة أساسية تثبت مصادقة المستخدم بنجاح باستخدام عامله الأول.

    على سبيل المثال، إذا كان العامل الأول للمستخدم هو البريد الإلكتروني وكلمة المرور:

    try {
      await _auth.signInWithEmailAndPassword(
          email: emailController.text,
          password: passwordController.text,
      );
      // User is not enrolled with a second factor and is successfully
      // signed in.
      // ...
    } on FirebaseAuthMultiFactorException catch (e) {
      // The user is a multi-factor user. Second factor challenge is required
      final resolver = e.resolver
      // ...
    }
    
  2. إذا كان المستخدم لديه عدة عوامل ثانوية مسجلة، فاسأله عن العامل الذي يجب استخدامه:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. أرسل رسالة تحقق إلى هاتف المستخدم مع التلميح وجلسة متعددة العوامل:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. يمكنك الاتصال بالرقم resolver.resolveSignIn() لإكمال المصادقة الثانوية:

    final smsCode = await getSmsCodeFromUser(context);
    if (smsCode != null) {
      // Create a PhoneAuthCredential with the code
      final credential = PhoneAuthProvider.credential(
        verificationId: verificationId,
        smsCode: smsCode,
      );
    
      try {
        await e.resolver.resolveSignIn(
          PhoneMultiFactorGenerator.getAssertion(credential)
        );
      } on FirebaseAuthException catch (e) {
        print(e.message);
      }
    }
    

يوضح الرمز أدناه مثالاً كاملاً لتسجيل دخول مستخدم متعدد العوامل:

try {
  await _auth.signInWithEmailAndPassword(
    email: emailController.text,
    password: passwordController.text,
  );
} on FirebaseAuthMultiFactorException catch (e) {
  setState(() {
    error = '${e.message}';
  });
  final firstHint = e.resolver.hints.first;
  if (firstHint is! PhoneMultiFactorInfo) {
    return;
  }
  await FirebaseAuth.instance.verifyPhoneNumber(
    multiFactorSession: e.resolver.session,
    multiFactorInfo: firstHint,
    verificationCompleted: (_) {},
    verificationFailed: (_) {},
    codeSent: (String verificationId, int? resendToken) async {
      // See `firebase_auth` example app for a method of retrieving user's sms code: 
      // https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
      final smsCode = await getSmsCodeFromUser(context);

      if (smsCode != null) {
        // Create a PhoneAuthCredential with the code
        final credential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: smsCode,
        );

        try {
          await e.resolver.resolveSignIn(
            PhoneMultiFactorGenerator.getAssertion(
              credential,
            ),
          );
        } on FirebaseAuthException catch (e) {
          print(e.message);
        }
      }
    },
    codeAutoRetrievalTimeout: (_) {},
  );
} catch (e) {
  ...
} 

تهانينا لقد نجحت في تسجيل دخول مستخدم باستخدام المصادقة متعددة العوامل.

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