使用電話號碼和 C++ 進行 Firebase 驗證

您可以使用 Firebase 驗證功能,透過傳送簡訊到使用者的手機登入使用者。使用者使用簡訊中的一次性代碼登入。

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

事前準備

  1. 將 Firebase 新增至您的 C++ 專案
  2. 如果您尚未將應用程式連結至 Firebase 專案,請透過 Firebase 控制台進行。
  3. 瞭解電話號碼登入平台的相關規定:
    • 電話號碼登入功能僅適用於行動平台。
    • 在 iOS 裝置上,電話號碼登入需要使用實體裝置,且無法在模擬器上運作。

安全疑慮

僅使用電話號碼進行驗證,但比其他可用的方法更安全,因為使用者可以在使用者之間輕鬆轉移電話號碼。此外,如果裝置上有多個使用者設定檔,任何可接收簡訊的使用者,都能使用裝置的電話號碼登入帳戶。

如果您在應用程式中使用以電話號碼為基礎的登入功能,建議您除了提供更安全的登入方式之外,也應向使用者說明使用電話號碼登入機制在安全性方面的保障。

為 Firebase 專案啟用電話號碼登入功能

如要透過簡訊登入使用者,您必須先為 Firebase 專案啟用電話號碼登入方式:

  1. Firebase 控制台開啟「驗證」專區。
  2. 在「Sign-in Method」(登入方式) 頁面中,啟用「Phone Number」(電話號碼) 登入方式。

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

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

如要在 Apple 平台上使用電話號碼驗證機制,您的應用程式必須能夠接收來自 Firebase 的 APN 通知。當您首次在裝置上以電話號碼登入使用者時,Firebase 驗證會向裝置傳送無訊息推送通知,驗證應用程式是否由應用程式發出電話號碼登入要求 (因此,模擬器不支援電話號碼登入功能)。

如何啟用與 Firebase 驗證搭配使用的 APN 通知:

  1. 在 Xcode 中,為專案 啟用推播通知
  2. 將 APN 憑證上傳至 Firebase。如果您還沒有 APN 憑證,請務必前往 Apple Developer Member Center 建立 APN 憑證。

    1. 在 Firebase 控制台的專案中,依序選取齒輪圖示 >「專案設定」,然後選取「雲端通訊」分頁標籤。

    2. 選取開發憑證和/或正式版憑證的 [上傳憑證] 按鈕。至少須提供一個。

    3. 為每個憑證選取 .p12 檔案,並提供密碼 (如果有的話)。確認這個憑證的軟體包 ID 與應用程式的軟體包 ID 相符。請選取「儲存」

將驗證碼傳送至使用者的手機

如要啟動電話號碼登入程序,請向使用者顯示提示,提示他們提供電話號碼,然後呼叫 PhoneAuthProvider::VerifyPhoneNumber 以要求 Firebase 透過簡訊將驗證碼傳送至使用者的手機:

  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 裝置上) 傳送無聲推播通知至您的應用程式。
    • 傳送含有驗證碼的簡訊至指定的電話號碼,並將驗證 ID 傳送至完成函式。您需要驗證碼和驗證 ID,才能登入使用者。
  3. 儲存驗證 ID,並在應用程式載入時還原驗證 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 即時資料庫和 Cloud Storage 安全性規則中,您可以透過 auth 變數取得登入使用者的專屬 ID,並使用該 ID 控管使用者可存取哪些資料。

您可以將驗證供應商憑證連結至現有的使用者帳戶,讓使用者透過多個驗證服務提供者登入您的應用程式。

如要登出使用者,請呼叫 SignOut()

auth->SignOut();