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

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

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

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

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

חששות לגבי אבטחה

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

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

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

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

  1. במסוף Firebase, פותחים את הקטע Authentication (אימות).
  2. בדף שיטת הכניסה, מפעילים את שיטת הכניסה באמצעות מספר טלפון.
  3. אופציונלי: בדף הגדרות, מגדירים מדיניות לגבי האזורים שבהם רוצים לאפשר או לאסור שליחת הודעות SMS. הגדרת מדיניות אזורית ל-SMS יכולה לעזור להגן על האפליקציות מפני ניצול לרעה של SMS.
  4. באותו דף, אם הדומיין שיארח את האפליקציה לא מופיע בקטע דומיינים להפניה אוטומטית של OAuth, מוסיפים את הדומיין. הערה: אי אפשר להשתמש ב-localhost כדומיין מתארח לצורך אימות טלפוני.

הגדרת מאמת reCAPTCHA

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

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

אובייקט RecaptchaVerifier תומך ב-invisible 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();

שימוש ב-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

אפשר להגדיר פונקציות קריאה חוזרת באובייקט 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;
});

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

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. לאחר מכן, נכנסים לחשבון של המשתמש על ידי העברת הקוד לשיטה confirm של האובייקט ConfirmationResult שהועבר ל-handler של 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 בפועל.
  • להריץ בדיקות רצופות עם אותו מספר טלפון בלי שהמערכת תגביל את מספר הבדיקות. השיטה הזו מצמצמת את הסיכון לדחייה במהלך תהליך הבדיקה של חנות האפליקציות, אם הבודק משתמש באותו מספר טלפון לבדיקה.
  • אפשר לבצע בדיקות בקלות בסביבות פיתוח ללא מאמץ נוסף, למשל לפתח באמולטור iOS או באמולטור Android ללא Google Play Services.
  • לכתוב בדיקות שילוב בלי להיחסם על ידי בדיקות אבטחה שבדרך כלל מופעלות על מספרי טלפון אמיתיים בסביבת ייצור.

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

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

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

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

בדיקה ידנית

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

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

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

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

בדיקות שילוב

בנוסף לבדיקות ידניות, 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 יפוג אחרי זמן מה, ואז הבעיה תיפתר שוב באופן אוטומטי.
  • reCAPTCHA נסתר: ה-reCAPTCHA הנסתר לא נפתר אוטומטית בזמן העיבוד, אלא בזמן הקריאה ל-appVerifier.verify() או כשלוחצים על לחצן העוגן של ה-reCAPTCHA אחרי השהיה של חלקיק שנייה. באופן דומה, תוקף התגובה יפוג אחרי זמן מסוים, והיא תיפתר באופן אוטומטי רק אחרי הקריאה של appVerifier.verify() או כשלוחצים שוב על לחצן העוגן של ה-reCAPTCHA.

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

השלבים הבאים

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

  • באפליקציות, הדרך המומלצת לדעת מה סטטוס האימות של המשתמש היא להגדיר אובייקט observer ב-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.
});