בצע אימות עם 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 version 9

      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 version 8

      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 version 9

    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 version 8

    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 version 9

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 version 8

// 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 version 9

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 version 8

// 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 version 9

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 version 8

// 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 המשתמש.

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

Web version 9

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 version 8

// 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 ואחסון בענן , תוכל לקבל את מזהה המשתמש הייחודי של המשתמש auth ממשתנה האימות, ולהשתמש בו כדי לשלוט לאילו נתונים המשתמש יכול לגשת.

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

כדי לצאת ממשתמש, התקשר signOut :

Web version 9

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

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

Web version 8

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