אימות עם Firebase באמצעות קישור דוא"ל ב-JavaScript

אתה יכול להשתמש ב-Firebase Authentication כדי להיכנס למשתמש על ידי שליחת דוא"ל המכיל קישור, עליו הם יכולים ללחוץ כדי להיכנס. בתהליך, כתובת הדוא"ל של המשתמש מאומתת גם.

ישנן יתרונות רבים לכניסה בדוא"ל:

  • הרשמה וכניסה לחיכוך נמוך.
  • סיכון נמוך יותר לשימוש חוזר בסיסמאות בין יישומים, מה שעלול לערער את האבטחה אפילו של סיסמאות שנבחרו היטב.
  • היכולת לאמת משתמש תוך אימות שהמשתמש הוא הבעלים הלגיטימי של כתובת אימייל.
  • משתמש צריך רק חשבון דוא"ל נגיש כדי להיכנס. אין צורך בבעלות על מספר טלפון או חשבון מדיה חברתית.
  • משתמש יכול להיכנס בצורה מאובטחת ללא צורך לספק (או לזכור) סיסמה, מה שעלול להיות מסורבל במכשיר נייד.
  • משתמש קיים שנכנס בעבר עם מזהה דוא"ל (סיסמה או מאוחדת) יכול להשתדרג לכניסה באמצעות הדוא"ל בלבד. לדוגמה, משתמש ששכח את הסיסמה שלו עדיין יכול להיכנס ללא צורך לאפס את הסיסמה שלו.

לפני שאתה מתחיל

אם עדיין לא עשית זאת, העתק את קטע האתחול ממסוף Firebase לפרויקט שלך כמתואר בהוספת Firebase לפרויקט ה-JavaScript שלך .

כדי להיכנס למשתמשים באמצעות קישור דוא"ל, תחילה עליך להפעיל את שיטת הכניסה של ספק הדוא"ל ושיטת הכניסה לקישור דוא"ל עבור פרויקט Firebase שלך:

  1. במסוף Firebase , פתח את הקטע Auth .
  2. בכרטיסייה שיטת כניסה , הפעל את ספק הדוא"ל/סיסמה . שים לב שכניסה לדוא"ל/סיסמה חייבת להיות מופעלת כדי להשתמש בכניסה לקישור דוא"ל.
  3. באותו קטע, הפעל את שיטת הכניסה של קישור דוא"ל (כניסה ללא סיסמה) .
  4. לחץ על שמור .

כדי להתחיל את זרימת האימות, הצג למשתמש ממשק שמבקש מהמשתמש לספק את כתובת הדוא"ל שלו ולאחר מכן התקשר אל sendSignInLinkToEmail כדי לבקש מ-Firebase לשלוח את קישור האימות לאימייל של המשתמש.

  1. בנה את האובייקט ActionCodeSettings , המספק ל-Firebase הוראות כיצד לבנות את קישור הדוא"ל. הגדר את השדות הבאים:

    • url : הקישור העמוק להטמעה וכל מצב נוסף שיועבר. יש להוסיף את הדומיין של הקישור ברשימת הדומיינים המורשים של Firebase Console, אותה ניתן למצוא על ידי מעבר לכרטיסייה שיטת כניסה (אימות -> הגדרות).
    • android ו- ios : האפליקציות לשימוש כאשר קישור הכניסה נפתח במכשיר אנדרואיד או אפל. למד עוד כיצד להגדיר את Firebase Dynamic Links לפתיחת קישורי פעולות דוא"ל באמצעות אפליקציות לנייד.
    • handleCodeInApp : מוגדר כ-true. יש להשלים תמיד את פעולת הכניסה באפליקציה בניגוד לפעולות דוא"ל אחרות מחוץ לתחום (איפוס סיסמה ואימותי דוא"ל). הסיבה לכך היא שבסוף הזרימה, המשתמש צפוי להיות מחובר ומצב האימות שלו יישאר באפליקציה.
    • 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 מחייב לספק את כתובת האימייל של המשתמש בעת השלמת תהליך הכניסה. כדי שהכניסה תצליח, כתובת דוא"ל זו חייבת להתאים לכתובת שאליה נשלח קישור הכניסה במקור.

אתה יכול לייעל זרימה זו עבור משתמשים שפותחים את קישור הכניסה באותו מכשיר שהם מבקשים את הקישור, על ידי אחסון כתובת הדוא"ל שלהם באופן מקומי - למשל באמצעות localStorage או קובצי Cookie - כאשר אתה שולח את דוא"ל הכניסה. לאחר מכן, השתמש בכתובת זו כדי להשלים את הזרימה. אל תעביר את האימייל של המשתמש בפרמטרים של כתובת האתר להפניה מחדש ותעשה בו שימוש חוזר מכיוון שהדבר עלול לאפשר הזרקות הפעלה.

לאחר השלמת הכניסה, כל מנגנון כניסה לא מאומת קודם יוסר מהמשתמש וכל הפעלות קיימות יבוטלו. לדוגמה, אם מישהו יצר בעבר חשבון לא מאומת עם אותם דוא"ל וסיסמה, סיסמת המשתמש תוסר כדי למנוע מהמתחזה שטען לבעלות ויצר את החשבון הלא מאומת הזה להיכנס שוב עם האימייל והסיסמה הלא מאומתים.

כמו כן ודא שאתה משתמש בכתובת URL של HTTPS בייצור כדי למנוע את הקישור שלך שיירטו על ידי שרתי מתווכים.

השלמת כניסה בדף אינטרנט

הפורמט של הקישור העמוק של קישור הדוא"ל זהה לפורמט המשמש לפעולות דוא"ל מחוץ לתחום (אימות דוא"ל, איפוס סיסמה וביטול שינוי אימייל). Firebase Auth מפשט את הבדיקה הזו על ידי מתן ה-API isSignInWithEmailLink כדי לבדוק אם קישור הוא כניסה עם קישור דוא"ל.

כדי להשלים את הכניסה בדף הנחיתה, התקשר 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.
  });

עם זאת, מכיוון שהזרימה עלולה להסתיים במכשיר אחר שבו המשתמש המקורי לא היה מחובר, ייתכן שהזרימה הזו לא תושלם. במקרה זה, ניתן להציג שגיאה למשתמש כדי לאלץ אותו לפתוח את הקישור באותו מכשיר. ניתן להעביר מצב מסוים בקישור כדי לספק מידע על סוג הפעולה ו-uid המשתמש.

אם יצרת את הפרויקט שלך ב-15 בספטמבר 2023 או אחריו, הגנת ספירת דוא"ל מופעלת כברירת מחדל. תכונה זו משפרת את האבטחה של חשבונות המשתמש של הפרוייקט שלך, אך היא משביתה את שיטת fetchSignInMethodsForEmail() , עליה המלצנו בעבר ליישם זרימות מזהה-ראשון.

למרות שאתה יכול להשבית את ההגנה על ספירת דוא"ל עבור הפרויקט שלך, אנו ממליצים שלא לעשות זאת.

עיין בתיעוד על הגנת ספירת דוא"ל לפרטים נוספים.

תבנית ברירת מחדל לדוא"ל לכניסה לקישור

תבנית הדוא"ל המוגדרת כברירת מחדל כוללת חותמת זמן בנושא ובגוף הדוא"ל, כך שהודעות הדוא"ל הבאות לא יכווץ לשרשור אחד, כשהקישור מוסתר .

תבנית זו חלה על השפות הבאות:

קוד שפה
ar עֲרָבִית
zh-CN סינית מופשטת)
zh-TW מסורת סינית)
nl הוֹלַנדִי
he אנגלית
en-GB אנגלית בריטית)
fr צָרְפָתִית
דה גֶרמָנִיָת
תְעוּדַת זֶהוּת אינדונזית
זה אִיטַלְקִית
כן יַפָּנִית
קו קוריאנית
pl פולני
pt-BR פורטוגזית (ברזיל)
pt-PT פורטוגזית (פורטוגל)
ru רוּסִי
es ספרדית
es-419 ספרדית (אמריקה הלטינית)
ה' תאילנדית

הצעדים הבאים

לאחר שמשתמש נכנס בפעם הראשונה, נוצר חשבון משתמש חדש ומקושר לאישורים - כלומר, שם המשתמש והסיסמה, מספר הטלפון או פרטי ספק האישור - המשתמש נכנס איתו. החשבון החדש הזה מאוחסן כחלק מפרויקט Firebase שלך, וניתן להשתמש בו כדי לזהות משתמש בכל אפליקציה בפרויקט שלך, ללא קשר לאופן שבו המשתמש נכנס.

  • באפליקציות שלך, הדרך המומלצת לדעת את סטטוס ההרשאה של המשתמש שלך היא להגדיר צופה על אובייקט Auth . לאחר מכן תוכל לקבל את פרטי הפרופיל הבסיסיים של המשתמש מאובייקט User . ראה ניהול משתמשים .

  • בכללי האבטחה של מסד הנתונים בזמן אמת של Firebase ואחסון בענן , אתה יכול לקבל את מזהה המשתמש הייחודי של המשתמש המחובר ממשתנה 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.
});