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

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

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

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

قبل البدء

إعداد مشروع Android

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

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

    وكجزء من إعداد مصادقة Firebase أيضًا، يلزمك إضافة حزمة SDK لخدمات Google Play إلى تطبيقك.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
    
        // 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.2.0")
    }

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

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

    إذا اخترت عدم استخدام قائمة العناصر في Firebase، يجب تحديد كل إصدار من مكتبة 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.0.0")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.2.0")
    }
    هل تبحث عن وحدة مكتبة خاصة بلغة Kotlin؟ اعتبارًا من تشرين الأول (أكتوبر) 2023 (الإصدار 32.5.0 من Firebase)، أصبح بإمكان مطوّري لغة Kotlin وJava الاعتماد على وحدة المكتبة الرئيسية (لمعرفة التفاصيل، يُرجى الاطّلاع على الأسئلة الشائعة حول هذه المبادرة).

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

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

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

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

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

    Kotlin+KTX

    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+KTX

    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" تقديم عنوان البريد الإلكتروني للمستخدم عند إكمال عملية تسجيل الدخول. لنجاح عملية تسجيل الدخول، يجب أن يتطابق عنوان البريد الإلكتروني هذا مع العنوان الذي تم إرسال رابط تسجيل الدخول إليه في الأصل.

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

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

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

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

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

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

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

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

      إذا سبق لك إنشاء نطاق "روابط ديناميكية"، دوِّنه. يظهر نطاق الروابط الديناميكية عادةً على النحو التالي:

      example.page.link

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

  2. تهيئة تطبيقات Android:

    1. لمعالجة هذه الروابط من تطبيق Android، يجب تحديد اسم حزمة Android في إعدادات المشروع في وحدة تحكُّم Firebase. بالإضافة إلى ذلك، يلزم تقديم خوارزمية 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+KTX

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+KTX

// 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+KTX

// 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 في الوقت الفعلي وقواعد أمان Cloud Storage، يمكنك الحصول على رقم تعريف المستخدم الفريد للمستخدم الذي سجّل الدخول من المتغيّر auth واستخدامه للتحكّم في البيانات التي يمكن للمستخدم الوصول إليها.

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

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

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();