المصادقة في Firebase باستخدام رابط البريد الإلكتروني في Android

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

هناك العديد من المزايا لتسجيل الدخول باستخدام عنوان البريد الإلكتروني:

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

قبل البدء

إعداد مشروع Android

  1. أضِف Firebase إلى مشروع Android، في حال لم يسبق لك إجراء ذلك.

  2. في ملف Gradle للوحدة (على مستوى التطبيق) (عادةً <project>/<app-module>/build.gradle.kts أو <project>/<app-module>/build.gradle)، أضِف الاعتمادية لمكتبة Firebase Authentication لنظام التشغيل Android. ننصحك باستخدام الرمز Firebase Android BoM للتحكّم في إصدارات المكتبة.

    بالإضافة إلى ذلك، كجزء من إعداد Firebase Authentication، عليك إضافة حزمة تطوير البرامج (SDK) لـ "خدمات Google Play" إلى تطبيقك.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.7.0"))
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.3.0")
    }

    باستخدام Firebase Android BoM، سيستخدم تطبيقك دائمًا إصدارات متوافقة من مكتبات Firebase لنظام التشغيل Android.

    (بديل)  إضافة تبعيات مكتبة Firebase بدون استخدام BoM

    إذا اخترت عدم استخدام Firebase BoM، يجب تحديد كل إصدار من مكتبة Firebase في سطر التبعية الخاص به.

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

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth:23.1.0")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.3.0")
    }
    هل تبحث عن وحدة مكتبة خاصة بلغة Kotlin؟ اعتبارًا من تشرين الأول (أكتوبر) 2023 (Firebase BoM 32.5.0)، يمكن لمطوّري Kotlin وJava الاعتماد على وحدة المكتبة الرئيسية (للاطّلاع على التفاصيل، راجِع الأسئلة الشائعة حول هذه المبادرة).

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

  1. في وحدة تحكّم Firebase، افتح قسم Auth.
  2. في علامة التبويب طريقة تسجيل الدخول، فعِّل موفِّر البريد الإلكتروني/كلمة المرور. يُرجى العلم أنّه يجب تفعيل ميزة تسجيل الدخول باستخدام عنوان البريد الإلكتروني وكلمة المرور لاستخدام ميزة تسجيل الدخول باستخدام رابط البريد الإلكتروني.
  3. في القسم نفسه، فعِّل رابط البريد الإلكتروني (تسجيل الدخول بدون كلمة مرور).
  4. انقر على حفظ.

لبدء عملية المصادقة، عليك عرض واجهة على المستخدم تطلب منه تقديم عنوان بريده الإلكتروني، ثم الاتصال بـ sendSignInLinkToEmail لطلب أن ترسل Firebase رابط المصادقة إلى بريد المستخدم الإلكتروني.

  1. أنشئ عنصر ActionCodeSettings الذي يقدّم لـ Firebase تعليمات حول كيفية إنشاء رابط البريد الإلكتروني. اضبط الحقول التالية:

    • url: الرابط لصفحة في التطبيق المطلوب تضمينه وأي حالة إضافية المطلوب تمريرها يجب أن يكون نطاق الرابط مُدرَجًا في القائمة المسموح بها في "وحدة تحكّم Firebase" للنطاقات المعتمَدة، والتي يمكن العثور عليها من خلال الانتقال إلى علامة التبويب "طريقة تسجيل الدخول" (المصادقة -> طريقة تسجيل الدخول). سيعيد الرابط توجيه المستخدم إلى عنوان URL هذا إذا لم يكن التطبيق مثبّتًا على جهازه ولم يكن بإمكانه تثبيته.
    • androidPackageName وIOSBundleId: التطبيقات المُستخدَمة عند فتح ملف تعريف الارتباط لتسجيل الدخول على جهاز Android أو Apple اطّلِع على مزيد من المعلومات عن كيفية ضبط روابط Firebase الديناميكية لفتح روابط الإجراءات في الرسائل الإلكترونية من خلال التطبيقات المتوافقة مع الأجهزة الجوّالة.
    • handleCodeInApp: يتم ضبطها على true. يجب إكمال عملية تسجيل الدخول دائمًا في التطبيق على عكس الإجراءات الأخرى التي تتم خارج نطاق البريد الإلكتروني (مثل إعادة ضبط كلمة المرور وإثبات ملكية البريد الإلكتروني). ويعود السبب في ذلك إلى أنّه في نهاية العملية، من المتوقّع أن يكون المستخدم مسجِّلاً الدخول وأن تظل حالة المصادقة محفوظة في التطبيق.
    • dynamicLinkDomain: عند تحديد نطاقات متعددة للروابط الديناميكية المخصّصة لمشروع معيّن، حدِّد النطاق الذي تريد استخدامه عند فتح الرابط من خلال تطبيق جوّال محدّد (على سبيل المثال، example.page.link). وإلا، سيتم تحديد النطاق الأول تلقائيًا.

    Kotlin

    val actionCodeSettings = actionCodeSettings {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url = "https://www.example.com/finishSignUp?cartId=1234"
        // This must be true
        handleCodeInApp = true
        setIOSBundleId("com.example.ios")
        setAndroidPackageName(
            "com.example.android",
            true, // installIfNotAvailable
            "12", // minimumVersion
        )
    }

    Java

    ActionCodeSettings actionCodeSettings =
            ActionCodeSettings.newBuilder()
                    // URL you want to redirect back to. The domain (www.example.com) for this
                    // URL must be whitelisted in the Firebase Console.
                    .setUrl("https://www.example.com/finishSignUp?cartId=1234")
                    // This must be true
                    .setHandleCodeInApp(true)
                    .setIOSBundleId("com.example.ios")
                    .setAndroidPackageName(
                            "com.example.android",
                            true, /* installIfNotAvailable */
                            "12"    /* minimumVersion */)
                    .build();

    لمزيد من المعلومات عن ActionCodeSettings، يُرجى الرجوع إلى القسم تمرير الحالة في إجراءات الرسائل الإلكترونية.

  2. اطلب من المستخدم عنوان بريده الإلكتروني.

  3. أرسِل رابط المصادقة إلى عنوان البريد الإلكتروني للمستخدم، واحفظ عنوان البريد الإلكتروني للمستخدم في حال أكمل المستخدم عملية تسجيل الدخول باستخدام عنوان البريد الإلكتروني على الجهاز نفسه.

    Kotlin

    Firebase.auth.sendSignInLinkToEmail(email, actionCodeSettings)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Email sent.")
            }
        }

    Java

    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Email sent.");
                    }
                }
            });

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

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

يمكنك تبسيط هذه العملية للمستخدمين الذين يفتحون رابط تسجيل الدخول على الجهاز نفسه الذي طلبوا الرابط منه، وذلك من خلال تخزين عنوان بريدهم الإلكتروني على الجهاز - على سبيل المثال باستخدام SharedPreferences - عند إرسال الرسالة الإلكترونية لتسجيل الدخول. بعد ذلك، استخدِم هذا العنوان لإكمال عملية الإعداد. لا تُرسِل عنوان البريد الإلكتروني للمستخدم في مَعلمات عنوان URL لإعادة التوجيه ولا تُعيد استخدامه، لأنّه قد يؤدي ذلك إلى تفعيل عمليات إدخال الجلسات.

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

تأكَّد أيضًا من استخدام عنوان URL بتنسيق HTTPS في مرحلة الإنتاج لتجنُّب احتمال اعتراض الرابط من قِبل الخوادم الوسيطة.

إكمال عملية تسجيل الدخول في تطبيق Android

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

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

  1. فعِّل "روابط Firebase الديناميكية":

    1. في وحدة تحكّم Firebase، افتح قسم Dynamic Links.
    2. إذا لم يسبق لك قبول بنود Dynamic Links وإنشاء نطاق Dynamic Links ، يُرجى إجراء ذلك الآن.

      إذا سبق لك إنشاء نطاق Dynamic Links، عليك تدوينه. يظهر نطاق Dynamic Links عادةً بالشكل التالي:

      example.page.link

      ستحتاج إلى هذه القيمة عند ضبط تطبيق Apple أو Android لمحاولة اعتراض الرابط الوافد.

  2. ضبط تطبيقات Android:

    1. لمعالجة هذه الروابط من تطبيق Android، يجب تحديد اسم حزمة Android في إعدادات مشروع Firebase Console. بالإضافة إلى ذلك، يجب تقديم SHA-1 وSHA-256 لشهادة التطبيق.
    2. بعد إضافة نطاق رابط ديناميكي والتأكّد من ضبط إعدادات تطبيق Android بشكلٍ صحيح، سيعيد الرابط الديناميكي التوجيه إلى تطبيقك، بدءًا من نشاط مشغّل التطبيقات.
    3. إذا كنت تريد أن يعيد الرابط الديناميكي التوجيه إلى نشاط معيّن، عليك ضبط فلتر أهداف في ملف AndroidManifest.xml. ويمكن إجراء ذلك إما من خلال تحديد نطاق الرابط الديناميكي أو معالج الإجراء المطلوب من الرسالة الإلكترونية في فلتر الأهداف. يتم بشكلٍ تلقائي استضافة معالِج معالجة البريد الإلكتروني على نطاق مثل المثال التالي:
      PROJECT_ID.firebaseapp.com/
    4. التحذيرات:
      1. لا تحدِّد عنوان URL الذي ضبطته في actionCodeSettings في فلتر الأهداف.
      2. عند إنشاء نطاق الرابط الديناميكي، قد تكون أنشأت أيضًا رابط عنوان URL قصيرًا. لن يتم تمرير عنوان URL القصير هذا، لذا لا تضبط فلتر الأهداف لرصده باستخدام سمة android:pathPrefix. وهذا يعني أنّه لن تتمكّن من رصد روابط ديناميكية مختلفة في أجزاء مختلفة من تطبيقك. ومع ذلك، يمكنك التحقّق من مَعلمة طلب البحث mode في الرابط لمعرفة العملية التي يجري محاولة تنفيذها، أو استخدام طرق حزمة SDK، مثل isSignInWithEmailLink، لمعرفة ما إذا كان الرابط الذي تلقّاه تطبيقك يؤدي إلى ما تريده.
    5. لمزيد من المعلومات عن تلقّي الروابط الديناميكية، يُرجى الرجوع إلى تعليمات تلقّي الروابط الديناميكية على Android.

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

Kotlin

val auth = Firebase.auth
val intent = intent
val emailLink = intent.data.toString()

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    val email = "someemail@domain.com"

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Successfully signed in with email link!")
                val result = task.result
                // You can access the new user via result.getUser()
                // Additional user info profile *not* available via:
                // result.getAdditionalUserInfo().getProfile() == null
                // You can check if the user is new or existing:
                // result.getAdditionalUserInfo().isNewUser()
            } else {
                Log.e(TAG, "Error signing in with email link", task.exception)
            }
        }
}

Java

FirebaseAuth auth = FirebaseAuth.getInstance();
Intent intent = getIntent();
String emailLink = intent.getData().toString();

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    String email = "someemail@domain.com";

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Successfully signed in with email link!");
                        AuthResult result = task.getResult();
                        // You can access the new user via result.getUser()
                        // Additional user info profile *not* available via:
                        // result.getAdditionalUserInfo().getProfile() == null
                        // You can check if the user is new or existing:
                        // result.getAdditionalUserInfo().isNewUser()
                    } else {
                        Log.e(TAG, "Error signing in with email link", task.getException());
                    }
                }
            });
}

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

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

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

سيكون الفرق في النصف الثاني من العملية:

Kotlin

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Link the credential to the current user.
Firebase.auth.currentUser!!.linkWithCredential(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            Log.d(TAG, "Successfully linked emailLink credential!")
            val result = task.result
            // You can access the new user via result.getUser()
            // Additional user info profile *not* available via:
            // result.getAdditionalUserInfo().getProfile() == null
            // You can check if the user is new or existing:
            // result.getAdditionalUserInfo().isNewUser()
        } else {
            Log.e(TAG, "Error linking emailLink credential", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Link the credential to the current user.
auth.getCurrentUser().linkWithCredential(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Successfully linked emailLink credential!");
                    AuthResult result = task.getResult();
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error linking emailLink credential", task.getException());
                }
            }
        });

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

Kotlin

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Re-authenticate the user with this credential.
Firebase.auth.currentUser!!.reauthenticateAndRetrieveData(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            // User is now successfully reauthenticated
        } else {
            Log.e(TAG, "Error reauthenticating", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Re-authenticate the user with this credential.
auth.getCurrentUser().reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // User is now successfully reauthenticated
                } else {
                    Log.e(TAG, "Error reauthenticating", task.getException());
                }
            }
        });

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

إذا أنشأت مشروعك في 15 أيلول (سبتمبر) 2023 أو بعد هذا التاريخ، سيتم تفعيل الحماية ضد التعداد للعناوين الإلكترونية تلقائيًا. تحسِّن هذه الميزة أمان حسابات مستخدمي مشروعك، ولكنها تُوقِف طريقة fetchSignInMethodsForEmail() التي كنا ننصح بها سابقًا لتنفيذ عمليات الربط بالمعرّف أولاً.

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

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

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

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

  • في تطبيقاتك، يمكنك الحصول على معلومات الملف الشخصي الأساسية للمستخدم من عنصر FirebaseUser. راجِع إدارة المستخدِمين.

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

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

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

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();