אימות עם Firebase באמצעות מספר טלפון באמצעות JavaScript

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

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

לפני שמתחילים

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

בעיית אבטחה

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

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

הפעלת כניסה באמצעות מספר טלפון לפרויקט Firebase

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

  1. במסוף Firebase, פותחים את הקטע אימות.
  2. בדף Sign-in Method מפעילים את שיטת הכניסה Phone Number.
  3. באותו דף, אם הדומיין שיארח את האפליקציה לא מופיע דומיינים להפניה אוטומטית ב-OAuth, מוסיפים את הדומיין. לתשומת ליבך, אסור להשתמש ב-localhost כמארח מתארח דומיין למטרות אימות של מספר הטלפון.

הגדרת מאמת reCAPTCHA

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

אין צורך להגדיר באופן ידני לקוח reCAPTCHA. כשמשתמשים אובייקט RecaptchaVerifier של Firebase SDK, Firebase באופן אוטומטי יוצר ומטפל בכל מפתחות הלקוח והסודות הנדרשים.

האובייקט RecaptchaVerifier תומך בלתי נראה reCAPTCHA, שלרוב יכול לאמת את המשתמש בלי לדרוש משתמש כלשהו פעולה, וכן את הווידג'ט reCAPTCHA, תמיד דורש אינטראקציה של המשתמש עד שתסיימו את התהליך.

כדי להתאים את reCAPTCHA המורן לטעימה של המשתמש, אפשר לעדכן את קוד השפה במכונה של Auth לפני עיבוד ה-reCAPTCHA. ההתאמה לשוק המקומי שהוזכרה למעלה יחולו גם על הודעת ה-SMS שנשלחה למשתמש, המכילה את קוד האימות.

Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

שימוש ב-invisible reCAPTCHA

כדי להשתמש ב-reCAPTCHA נסתר, יוצרים אובייקט RecaptchaVerifier עם הפרמטר size שמוגדר כ-invisible, ומציינים את המזהה של הלחצן ששולח את טופס הכניסה. לדוגמה:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

שימוש בווידג'ט reCAPTCHA

כדי להשתמש בווידג'ט reCAPTCHA הגלוי, יוצרים בדף רכיב שיכיל את הווידג'ט, ואז יוצרים אובייקט RecaptchaVerifier ומציינים את המזהה של המאגר. לדוגמה:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

אופציונלי: ציון פרמטרים של reCAPTCHA

אפשר להגדיר פונקציות קריאה חוזרת (callback) מתבצעת קריאה לאובייקט RecaptchaVerifier כאשר המשתמש פותר את הבעיה התוקף של reCAPTCHA או של ה-reCAPTCHA לפני שהמשתמש שולח את הטופס:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

אופציונלי: עיבוד מראש של ה-reCAPTCHA

אם ברצונך לעבד מראש את ה-reCAPTCHA לפני שליחת בקשת כניסה, התקשרות אל render:

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

אחרי זיהוי הווידג'ט של reCAPTCHA, יוצג מזהה הווידג'ט של render. שאפשר להשתמש בהן כדי לבצע שיחות API של reCAPTCHA:

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

שליחת קוד אימות לטלפון של המשתמש

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

  1. מאתרים את מספר הטלפון של המשתמש.

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

  2. קוראים לפונקציה signInWithPhoneNumber ומעבירים אותה לטלפון של המשתמש ואת RecaptchaVerifier שיצרת קודם.

    Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    אם מתקבלת שגיאה ב-signInWithPhoneNumber, צריך לאפס את reCAPTCHA כדי שהמשתמש יוכל לנסות שוב:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });

השיטה signInWithPhoneNumber מנפיקה את אתגר ה-reCAPTCHA למשתמש, ואם הוא עובר את האתגר, מבקש Firebase Authentication תשלח הודעת SMS עם קוד אימות אל הטלפון של המשתמש.

כניסה לחשבון באמצעות קוד האימות

אחרי שהקריאה אל signInWithPhoneNumber תושלם, שולחים את הבקשה משתמש כדי להקליד את קוד האימות שקיבל ב-SMS. לאחר מכן, מעבירים את הקוד ל-method‏ confirm של האובייקט ConfirmationResult שהועברו למטפל ההשלמה של signInWithPhoneNumber (כלומר, לבלוק then שלו). לדוגמה:

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

אם הקריאה ל-confirm תצליח, המשתמש יתחבר בהצלחה.

אחזור אובייקט הביניים של AuthCredential

אם אתם צריכים לקבל אובייקט AuthCredential בשביל המשתמש נעביר את קוד האימות מתוצאת האישור את קוד האימות ל-PhoneAuthProvider.credential במקום התקשרות אל confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

לאחר מכן, אפשר להיכנס באמצעות פרטי הכניסה של המשתמש:

firebase.auth().signInWithCredential(credential);

בדיקה באמצעות מספרי טלפון בדיוניים

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

  • בדיקת אימות מספר טלפון בלי לנצל את מכסת השימוש.
  • אפשר לבדוק את אימות מספר הטלפון בלי לשלוח הודעת SMS אמיתית.
  • הפעלת בדיקות ברצף עם אותו מספר טלפון בלי ויסות נתונים (throttle). הזה מפחית את הסיכון לדחייה במהלך הבדיקה בחנות האפליקציות, אם הבודק משתמש את אותו מספר טלפון לבדיקה.
  • לבצע בדיקה מהירה בסביבות פיתוח ללא מאמץ נוסף, כמו את היכולת לפתח סימולטור של iOS או אמולטור Android ללא Google Play Services.
  • כתיבת בדיקות שילוב מבלי להיחסם על ידי בדיקות אבטחה שבדרך כלל מיושמות מספרי טלפון אמיתיים בסביבת הייצור.

מספרי טלפון בדיוניים חייבים לעמוד בדרישות הבאות:

  1. ודאו שאתם משתמשים במספרי טלפון בדיוניים, ושלא קיימים כבר. Firebase Authentication לא מאפשר לך להגדיר מספרי טלפון קיימים שמשמשים משתמשים אמיתיים כמספרי בדיקה. אפשרות אחת היא להשתמש בקידומת 555 כמספרי טלפון לבדיקה בארה"ב, לדוגמה: +1 650-555-3434
  2. מספרי הטלפון צריכים להיות בפורמט תקין לגבי אורך ואחרים מגבלות בפועל. הם עדיין יעברו את אותו תהליך אימות כמו מספר טלפון של משתמש אמיתי.
  3. אפשר להוסיף עד 10 מספרי טלפון לצורכי פיתוח.
  4. להשתמש במספרי טלפון/קודים לבדיקה שקשה לנחש ולשנות אותם אותן לעיתים קרובות.

יצירת מספרי טלפון וקודי אימות בדיוניים

  1. במסוף Firebase, פותחים את הקטע Authentication.
  2. בכרטיסייה Sign in method (שיטת כניסה), מפעילים את ספק הטלפון, אם עדיין לא עשיתם זאת.
  3. פותחים את התפריט הנפתח מספרי טלפון לבדיקה.
  4. מזינים את מספר הטלפון שרוצים לבדוק, לדוגמה: +1 650-555-3434.
  5. מזינים את קוד האימות בן 6 הספרות של המספר הספציפי הזה, לדוגמה: 654321.
  6. מוסיפים את המספר. במקרה הצורך, אפשר למחוק את מספר הטלפון בקוד שלו, מעבירים את העכבר מעל השורה המתאימה ולוחצים על סמל האשפה.

בדיקה ידנית

תוכלו להתחיל להשתמש במספר טלפון בדיוני ישירות בטופס הבקשה. כך אפשר לבצע בדיקות ידניות במהלך שלבי הפיתוח, בלי להיתקל בבעיות מכסה או ויסות נתונים (throttle). אפשר גם לבצע בדיקה ישירות מסימולטור של iOS או מאמולטור Android ללא Google Play Services מותקנת.

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

בסיום הכניסה, נוצר משתמש ב-Firebase עם מספר הטלפון הזה. למשתמש יש התנהגות ומאפיינים זהים לאלה של משתמש אמיתי של מספר טלפון, והוא יכול לגשת Realtime Database/Cloud Firestore ושירותים אחרים באותו אופן. האסימון המזהה שנוצר במהלך בתהליך הזה יש את אותה חתימה כמו של משתמש אמיתי במספר טלפון.

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

בדיקת אינטגרציה

בנוסף לבדיקות ידניות, יש ב-Firebase Authentication ממשקי API שעוזרים לכתוב בדיקות שילוב לבדיקת אימות הטלפון. ממשקי ה-API האלה משביתים את אימות האפליקציות על ידי השבתת ה-reCAPTCHA דרישה באימייל והתראות שקטות ב-iOS. כך אפשר לבצע בדיקות אוטומציה את התהליכים האלה וקל יותר ליישם אותם. בנוסף, הן מאפשרות לבצע בדיקה מיידית ב-Android.

באינטרנט, צריך להגדיר את appVerificationDisabledForTesting לערך true לפני רינדור firebase.auth.RecaptchaVerifier. הפעולה הזו פותרים את הבעיה ה-reCAPTCHA באופן אוטומטי, כך שתוכלו להעביר את מספר הטלפון בלי לפתור את הבעיה באופן ידני. הערה למרות ש-reCAPTCHA מושבת, השימוש במספר טלפון לא בדיוני עדיין לא יפעל. להשלים את תהליך הכניסה. באמצעות ה-API הזה ניתן להשתמש רק במספרי טלפון בדיוניים.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

מאמתי אפליקציות של reCAPTCHA אפליקציות גלויים או בלתי נראים מתנהגים באופן שונה כאשר אימות האפליקציה מושבת:

  • reCAPTCHA גלוי: כשה-reCAPTCHA הגלוי מנוהל באמצעות appVerifier.render(), הוא נפתר באופן אוטומטי לאחר עיכוב של חלקיק שנייה. הפעולה הזו מקבילה למשתמש שלוחצים על ה-reCAPTCHA מיד לאחר הרינדור. ה-reCAPTCHA התגובה תפוג לאחר זמן מה ואז תטופל שוב באופן אוטומטי.
  • Invisible reCAPTCHA: ה-Invisible reCAPTCHA לא נפתר באופן אוטומטי במהלך העיבוד, אלא בקריאה appVerifier.verify() או כשלוחצים על לחצן העוגן של ה-reCAPTCHA לאחר עיכוב של חלקיק שנייה. באופן דומה, תוקף התשובה יפוג לאחר זמן מה תיפתר באופן אוטומטי רק אחרי הקריאה ל-appVerifier.verify() או כאשר לחצן עוגן הלחצן של ה-reCAPTCHA מופעל שוב.

במקרה של דוגמת reCAPTCHA, פונקציית הקריאה החוזרת המתאימה מופעלת כמצופה עם התשובה המזויפת. אם תצוין גם קריאה חוזרת (callback) של תפוגה, היא תופעל כאשר יפוג תוקף.

השלבים הבאים

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

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

  • בתוך Firebase Realtime Database ו-Cloud Storage כללי אבטחה – מקבלים את מזהה המשתמש הייחודי של המשתמש המחובר מהמשתנה auth, ולהשתמש בהם כדי לקבוע לאילו נתונים המשתמש יוכל לגשת.

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

כדי לנתק משתמש מהחשבון, יש להתקשר אל signOut:

Web

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

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

Web

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