使用 JavaScript 透過電話號碼透過 Firebase 進行身份驗證

您可以使用 Firebase 身份驗證,透過向使用者的手機發送簡訊來登入使用者。使用者使用 SMS 訊息中包含的一次性代碼登入。

將電話號碼登入新增至應用程式最簡單的方法是使用FirebaseUI ,其中包括一個下拉登入小部件,該小部件可實現電話號碼登入的登入流程以及基於密碼的聯合登入。本文檔說明如何使用 Firebase SDK 實作電話號碼登入流程。

在你開始之前

如果您尚未將初始化程式碼片段從Firebase 控制台複製到您的項目,請依照將 Firebase 新增至您的 JavaScript 專案中所述。

安全問題

僅使用電話號碼進行身份驗證雖然方便,但安全性低於其他可用方法,因為電話號碼的所有權可以在用戶之間輕鬆轉移。此外,在具有多個使用者設定檔的裝置上,任何可以接收 SMS 訊息的使用者都可以使用裝置的電話號碼登入帳戶。

如果您在應用程式中使用基於電話號碼的登入方式,則應與更安全的登入方法一起提供,並告知使用者使用電話號碼登入的安全性權衡。

為您的 Firebase 專案啟用電話號碼登錄

若要透過簡訊登入用戶,您必須先為您的 Firebase 專案啟用電話號碼登入方法:

  1. Firebase 控制台中,開啟「驗證」部分。
  2. 登入方法頁面上,啟用電話號碼登入方法。
  3. 在同一頁面上,如果OAuth 重定向網域部分中未列出將託管您的應用程式的網域,請新增您的網域。

Firebase 的電話號碼登入請求配額足夠高,大多數應用程式不會受到影響。但是,如果您需要透過電話驗證登入大量用戶,則可能需要升級定價方案。請參閱定價頁面。

設定 reCAPTCHA 驗證程序

您必須先設定 Firebase 的 reCAPTCHA 驗證程序,然後才能使用電話號碼登入使用者。 Firebase 使用 reCAPTCHA 來防止濫用,例如確保電話號碼驗證請求來自應用程式允許的網域之一。

您無需手動設定 reCAPTCHA 用戶端;當您使用 Firebase SDK 的RecaptchaVerifier物件時,Firebase 會自動建立並處理任何必要的用戶端金鑰和機密。

RecaptchaVerifier物件支援不可見的 reCAPTCHA ,它通常可以驗證使用者而不需要任何使用者操作,以及 reCAPTCHA 小部件,它總是需要使用者互動才能成功完成。

透過在渲染 reCAPTCHA 之前更新 Auth 實例上的語言程式碼,可以將底層渲染的 reCAPTCHA 本地化為使用者的首選項。上述本地化也適用於發送給用戶的包含驗證碼的簡訊。

Web modular API

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 namespaced API

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

使用隱形 reCAPTCHA

若要使用不可見的 reCAPTCHA,請建立一個RecaptchaVerifier對象,並將size參數設為invisible ,並指定提交登入表單的按鈕的 ID。例如:

Web modular API

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 namespaced API

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

使用 reCAPTCHA 小部件

若要使用可見的 reCAPTCHA 小部件,請在頁面上建立一個元素來包含該小部件,然後建立一個RecaptchaVerifier對象,並在執行此操作時指定容器的 ID。例如:

Web modular API

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

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

Web namespaced API

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

可選:指定 reCAPTCHA 參數

您可以選擇在RecaptchaVerifier物件上設定回呼函數,當使用者解決 reCAPTCHA 或 reCAPTCHA 在使用者提交表單之前過期時呼叫這些回呼函數:

Web modular API

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 namespaced API

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 modular API

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

Web namespaced API

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

render解析後,您將獲得 reCAPTCHA 的小部件 ID,您可以使用它來呼叫reCAPTCHA API:

Web modular API

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web namespaced API

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

發送驗證碼至用戶手機

要啟動電話號碼登錄,請向用戶顯示一個介面,提示他們提供電話號碼,然後呼叫signInWithPhoneNumber來請求 Firebase 透過 SMS 向用戶的手機發送身份驗證代碼:

  1. 取得用戶的電話號碼。

    法律要求各不相同,但作為最佳實踐並為用戶設定期望,您應該告知他們,如果他們使用電話登錄,他們可能會收到一條用於驗證的短信,並且適用標準費率。

  2. 呼叫signInWithPhoneNumber ,將使用者的電話號碼和您先前建立的RecaptchaVerifier傳遞給它。

    Web modular API

    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 namespaced API

    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 驗證將包含驗證碼的 SMS 訊息傳送到使用者的手機。

使用驗證碼登入用戶

signInWithPhoneNumber的呼叫成功後,提示使用者輸入透過簡訊收到的驗證碼。然後,透過將程式碼傳遞到ConfirmationResult物件的confirm方法來登入用戶,該方法已傳遞到signInWithPhoneNumber的履行處理程序(即其then區塊)。例如:

Web modular API

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 namespaced API

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 控制台設定用於開發的虛構電話號碼。使用虛構電話號碼進行測試具有以下優點:

  • 測試電話號碼身份驗證而不消耗您的使用配額。
  • 在不發送實際簡訊的情況下測試電話號碼身份驗證。
  • 使用相同的電話號碼執行連續測試而不會受到限制。如果審核者碰巧使用相同的電話號碼進行測試,這可以最大限度地降低應用程式商店審核過程中被拒絕的風險。
  • 無需任何額外工作即可在開發環境中輕鬆進行測試,例如無需 Google Play 服務即可在 iOS 模擬器或 Android 模擬器中進行開發。
  • 編寫整合測試,而不會被通常應用於生產環境中真實電話號碼的安全檢查所阻止。

虛構電話號碼必須符合以下要求:

  1. 確保您使用的電話號碼確實是虛構的且不存在。 Firebase 驗證不允許您將真實使用者使用的現有電話號碼設定為測試號碼。一種選擇是使用 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 服務。

當您提供虛構的電話號碼並發送驗證碼時,不會發送實際的簡訊。相反,您需要提供先前配置的驗證碼才能完成登入。

登入完成後,系統會使用該電話號碼建立 Firebase 使用者。使用者俱有與真實電話號碼使用者相同的行為和屬性,並且可以以相同的方式存取即時資料庫/Cloud Firestore 和其他服務。在此過程中產生的 ID 令牌與真實電話號碼使用者俱有相同的簽名。

如果您想進一步限制訪問,另一種選擇是透過自訂聲明對這些用戶設定測試角色,以將他們區分為假用戶。

整合測試

除了手動測試之外,Firebase 驗證還提供 API 來協助編寫電話身份驗證測試的整合測試。這些 API 透過停用 Web 中的 reCAPTCHA 要求和 iOS 中的靜默推播通知來停用應用程式驗證。這使得這些流程中的自動化測試成為可能並且更容易實施。此外,它們還有助於提供在 Android 上測試即時驗證流程的能力。

在 Web 上,在渲染firebase.auth.RecaptchaVerifier之前將appVerificationDisabledForTesting設定為true 。這會自動解析 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 :當透過appVerifier.render()渲染可見的 reCAPTCHA 時,它會在幾分之一秒的延遲後自動解析。這相當於用戶在渲染後立即點擊 reCAPTCHA。 reCAPTCHA 回應將在一段時間後過期,然後再次自動解析。
  • 不可見的 reCAPTCHA :不可見的 reCAPTCHA 不會在渲染時自動解析,而是在呼叫appVerifier.verify()時或在幾分之一秒的延遲後點擊 reCAPTCHA 的按鈕錨點時自動解析。同樣,回應將在一段時間後過期,並且僅在呼叫appVerifier.verify()後或再次點擊 reCAPTCHA 的按鈕錨點時才會自動解析。

每當模擬 reCAPTCHA 被解析時,對應的回呼函數就會如預期地觸發假響應。如果也指定了過期回調,它將在過期時觸發。

下一步

使用者首次登入後,系統會建立新的使用者帳戶,並將其連結到使用者登入時所使用的憑證(即使用者名稱和密碼、電話號碼或驗證提供者資訊)。此新帳戶將作為 Firebase 專案的一部分存儲,並且可用於識別專案中每個應用程式中的用戶,無論用戶如何登入。

  • 在您的應用程式中,了解使用者的身份驗證狀態的建議方法是在Auth物件上設定觀察者。然後,您可以從User物件取得使用者的基本個人資料資訊。請參閱管理用戶

  • 在 Firebase 即時資料庫和雲端儲存安全性規則中,您可以從auth變數取得登入使用者的唯一使用者 ID,並使用它來控制使用者可以存取哪些資料。

您可以透過將身分驗證提供者憑證連結到現有使用者帳戶,允許使用者使用多個驗證提供者登入您的應用程式。

若要登出用戶,請呼叫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.
});