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

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

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

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

قبل ان تبدأ

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

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

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

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

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

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

      Web modular API

      const actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        dynamicLinkDomain: 'example.page.link'
      };

      Web namespaced API

      var actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        dynamicLinkDomain: 'example.page.link'
      };

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

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

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

    Web modular API

    import { getAuth, sendSignInLinkToEmail } from "firebase/auth";
    
    const auth = getAuth();
    sendSignInLinkToEmail(auth, email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        // ...
      });

    Web namespaced API

    firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        var errorCode = error.code;
        var errorMessage = error.message;
        // ...
      });

مخاوف أمنية

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

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

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

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

استكمال تسجيل الدخول في صفحة ويب

تنسيق الرابط الداخلي لرابط البريد الإلكتروني هو نفس التنسيق المستخدم لإجراءات البريد الإلكتروني خارج النطاق (التحقق من البريد الإلكتروني وإعادة تعيين كلمة المرور وإلغاء تغيير البريد الإلكتروني). يبسط Firebase Auth هذا الفحص من خلال توفير isSignInWithEmailLink API للتحقق مما إذا كان الارتباط عبارة عن رابط تسجيل دخول باستخدام بريد إلكتروني.

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

Web modular API

import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth";

// Confirm the link is a sign-in with email link.
const auth = getAuth();
if (isSignInWithEmailLink(auth, window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  let email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  signInWithEmailLink(auth, email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user via result.user
      // Additional user info profile not available via:
      // result.additionalUserInfo.profile == null
      // You can check if the user is new or existing:
      // result.additionalUserInfo.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

Web namespaced API

// Confirm the link is a sign-in with email link.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  var email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  firebase.auth().signInWithEmailLink(email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user via result.user
      // Additional user info profile not available via:
      // result.additionalUserInfo.profile == null
      // You can check if the user is new or existing:
      // result.additionalUserInfo.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

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

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

لمعرفة المزيد حول كيفية التعامل مع تسجيل الدخول باستخدام رابط البريد الإلكتروني في تطبيق Android ، راجع دليل Android .

لمعرفة المزيد حول كيفية التعامل مع تسجيل الدخول باستخدام رابط البريد الإلكتروني في تطبيق Apple ، راجع دليل أنظمة تشغيل Apple .

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

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

Web modular API

import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
const auth = getAuth();
linkWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web namespaced API

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
firebase.auth().currentUser.linkWithCredential(credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

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

Web modular API

import { getAuth, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
const auth = getAuth();
reauthenticateWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web namespaced API

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
firebase.auth().currentUser.reauthenticateWithCredential(credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

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

في حال كنت تدعم كلاً من كلمة المرور وتسجيل الدخول المستند إلى الارتباط بالبريد الإلكتروني ، للتمييز بين طريقة تسجيل الدخول لكلمة مرور / مستخدم رابط ، استخدم fetchSignInMethodsForEmail . يُعد هذا مفيدًا لعمليات تدفقات المعرف أولاً حيث يُطلب من المستخدم أولاً تقديم بريده الإلكتروني ثم تقديم طريقة تسجيل الدخول:

Web modular API

import { getAuth, fetchSignInMethodsForEmail, EmailAuthProvider} from "firebase/auth";

// After asking the user for their email.
const email = window.prompt('Please provide your email');

const auth = getAuth();
fetchSignInMethodsForEmail(auth, email)
  .then((signInMethods) => {
    // This returns the same array as fetchProvidersForEmail but for email
    // provider identified by 'password' string, signInMethods would contain 2
    // different strings:
    // 'emailLink' if the user previously signed in with an email/link
    // 'password' if the user has a password.
    // A user could have both.
    if (signInMethods.indexOf(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD) != -1) {
      // User can sign in with email/password.
    }
    if (signInMethods.indexOf(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD) != -1) {
      // User can sign in with email/link.
    }
  })
  .catch((error) => {
    // Some error occurred, you can inspect the code: error.code
  });

Web namespaced API

// After asking the user for their email.
var email = window.prompt('Please provide your email');
firebase.auth().fetchSignInMethodsForEmail(email)
  .then((signInMethods) => {
    // This returns the same array as fetchProvidersForEmail but for email
    // provider identified by 'password' string, signInMethods would contain 2
    // different strings:
    // 'emailLink' if the user previously signed in with an email/link
    // 'password' if the user has a password.
    // A user could have both.
    if (signInMethods.indexOf(
            firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD) != -1) {
      // User can sign in with email/password.
    }
    if (signInMethods.indexOf(
            firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD) != -1) {
      // User can sign in with email/link.
    }
  })
  .catch((error) => {
    // Some error occurred, you can inspect the code: error.code
  });

كما هو موضح أعلاه ، يعتبر البريد الإلكتروني / كلمة المرور والبريد الإلكتروني / الرابط نفس firebase.auth.EmailAuthProvider (نفس PROVIDER_ID ) مع طرق مختلفة لتسجيل الدخول.

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

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

  • في تطبيقاتك ، الطريقة الموصى بها لمعرفة حالة المصادقة للمستخدم الخاص بك هي تعيين مراقب على كائن Auth . يمكنك بعد ذلك الحصول على معلومات ملف التعريف الأساسية للمستخدم من كائن User . انظر إدارة المستخدمين .

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

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

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

Web modular API

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web namespaced API

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});