אימות עם 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 המקורי שעבר עיבוד, לפי העדפת המשתמש. לשם כך צריך לעדכן את את קוד השפה במופע האימות לפני רינדור ה-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

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

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