使用電話號碼和 C++ 透過 Firebase 進行身份驗證

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

本文檔說明如何使用 Firebase SDK 實作電話號碼登入流程。

在你開始之前

  1. 將 Firebase 新增到您的 C++ 專案
  2. 如果您尚未將應用程式連線至 Firebase 項目,請從Firebase 控制台執行此操作。
  3. 了解電話號碼登入的平台要求:
    • 電話號碼登入僅適用於行動平台。
    • 在 iOS 上,電話號碼登入需要實體設備,並且無法在模擬器上運行。

安全問題

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

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

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

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

  1. Firebase 控制台中,開啟「驗證」部分。
  2. 登入方法頁面上,啟用電話號碼登入方法。

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

開始接收 APNs 通知(Apple 平台)

要在 Apple 平台上使用電話號碼身份驗證,您的應用程式必須能夠從 Firebase 接收 APNs 通知。當您首次在裝置上使用電話號碼登入使用者時,Firebase 驗證會向裝置發送靜默推播通知,以驗證電話號碼登入要求是否來自您的應用程式。 (因此模擬器上無法使用電話號碼登入。)

若要啟用 APNs 通知以與 Firebase 驗證結合使用:

  1. 在 Xcode 中,為您的專案啟用推播通知
  2. 將您的 APNs 憑證上傳到 Firebase。如果您還沒有 APNs 證書,請務必在Apple 開發者會員中心建立一個。

    1. 在 Firebase 控制台的項目內,選擇齒輪圖標,選擇項目設置,然後選擇雲端訊息傳遞選項卡。

    2. 為您的開發證書、生產證書或兩者選擇「上傳證書」按鈕。至少需要一個。

    3. 對於每個證書,選擇 .p12 文件,並提供密碼(如果有)。確保此憑證的捆綁包 ID 與您的應用程式的捆綁包 ID 相符。選擇保存

發送驗證碼至用戶手機

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

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

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

  2. 呼叫PhoneAuthProvider::VerifyPhoneNumber ,向其傳遞使用者的電話號碼。
    class PhoneListener : public PhoneAuthProvider::Listener {
     public:
      ~PhoneListener() override {}
    
      void OnVerificationCompleted(PhoneAuthCredential credential) override {
        // Auto-sms-retrieval or instant validation has succeeded (Android only).
        // No need for the user to input the verification code manually.
        // `credential` can be used instead of calling GetCredential().
      }
    
      void OnVerificationFailed(const std::string& error) override {
        // Verification code not sent.
      }
    
      void OnCodeSent(const std::string& verification_id,
                      const PhoneAuthProvider::ForceResendingToken&
                          force_resending_token) override {
        // Verification code successfully sent via SMS.
        // Show the Screen to enter the Code.
        // Developer may want to save that verification_id along with other app states in case
        // the app is terminated before the user gets the SMS verification code.
      }
    };
    
    PhoneListener phone_listener;
    PhoneAuhtOptions options;
    options.timeout_milliseconds = kAutoVerifyTimeOut;
    options.phone_number = phone_number;
    PhoneAuthProvider& phone_provider = PhoneAuthProvider::GetInstance(auth);
    phone_provider->VerifyPhoneNumber(options, &phone_listener);
    
    當您呼叫PhoneAuthProvider::VerifyPhoneNumber 、 Firebase 時,
    • (在 iOS 上)向您的應用程式發送靜默推播通知,
    • 向指定的電話號碼傳送包含驗證碼的 SMS 訊息,並將驗證 ID 傳遞給您的完成函數。您將需要驗證碼和驗證 ID 來登入使用者。
  3. 保存驗證 ID 並在應用程式載入時恢復它。透過這樣做,如果您的應用程式在使用者完成登入流程之前終止(例如,切換到簡訊應用程式時),您可以確保您仍然擁有有效的驗證 ID。

    您可以以任何您想要的方式保留驗證 ID。如果您使用跨平台 C++ 框架進行編寫,它應該提供應用程式終止和復原的通知。在這些事件中,您可以分別儲存和還原驗證 ID。

如果對VerifyPhoneNumber呼叫導致偵聽器上呼叫OnCodeSent ,則您可以提示使用者在簡訊中收到驗證碼時輸入驗證碼。

另一方面,如果對VerifyPhoneNumber呼叫導致OnVerificationCompleted ,則自動驗證已成功,您現在將擁有一個PhoneAuthCredential ,您可以按如下所述使用它。

使用驗證碼登入用戶

用戶向您的應用程式提供簡訊中的驗證碼後,透過根據驗證碼和驗證 ID 建立PhoneAuthCredential物件並將該物件傳遞給Auth::SignInWithCredential來登入使用者。

  1. 取得用戶的驗證碼。
  2. 根據驗證碼和驗證 ID 建立Credential物件。
    PhoneAuthCredential credential = phone_auth_provider->GetCredential(
        verification_id_.c_str(), verification_code.c_str());
        
  3. 使用Credential物件登入使用者:
    Future<User> future = auth_->SignInWithCredential(credential);
    future.OnCompletion(
        [](const Future<User*>& result, void*) {
          if (result.error() == kAuthErrorNone) {
            // Successful.
            // User is signed in.
            User user = *result.result();
    
            // This should display the phone number.
            printf("Phone number: %s", user.phone_number().c_str());
    
            // The phone number provider UID is the phone number itself.
            printf("Phone provider uid: %s", user.uid().c_str());
    
            // The phone number providerID is 'phone'
            printf("Phone provider ID: %s", user.provider_id().c_str());
          } else {
            // Error.
            printf("Sign in error: %s", result.error_message().c_str());
          }
        },
        nullptr);
    

下一步

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

  • 在您的應用程式中,您可以從firebase::auth::User物件取得使用者的基本個人資料資訊:

    firebase::auth::User user = auth->current_user();
    if (user.is_valid()) {
      std::string name = user.display_name();
      std::string email = user.email();
      std::string photo_url = user.photo_url();
      // The user's ID, unique to the Firebase project.
      // Do NOT use this value to authenticate with your backend server,
      // if you have one. Use firebase::auth::User::Token() instead.
      std::string uid = user.uid();
    }
    
  • 在 Firebase 即時資料庫和雲端儲存安全性規則中,您可以從auth變數取得登入使用者的唯一使用者 ID,並使用它來控制使用者可以存取哪些資料。

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

若要登出用戶,請呼叫SignOut()

auth->SignOut();