電話番号と C++ を使用して Firebase 認証を行う

Firebase Authentication を使用すれば、ユーザーのスマートフォンに SMS メッセージを送信することによってユーザーをログインさせることができます。ユーザーは SMS メッセージに記載されたワンタイム コードを使用してログインします。

このドキュメントでは、Firebase SDK を使用して電話番号ログインのフローを実装する方法について説明します。

準備

  1. Firebase を C++ プロジェクトに追加します
  2. アプリを Firebase プロジェクトに接続していない場合は、Firebase コンソールで接続します。

iOS で電話番号ログインを行うには、物理端末が必要です。シミュレータでは機能しません。

セキュリティに関する懸念

電話番号の所有権はユーザー間で簡単に移転できるため、電話番号のみを使用する認証は、便利である反面、セキュリティ面では他の認証方法より劣ります。また、複数のユーザー プロフィールを持つ端末では、SMS メッセージを受信できるすべてのユーザーが、端末の電話番号を使用してアカウントにログインできます。

アプリで電話番号ベースのログインを使用する場合は、よりセキュリティの高いログイン方法も同時に提供し、電話番号ログインを使用した場合のセキュリティ面での懸念をユーザーに通知する必要があります。

Firebase プロジェクトで電話番号ログインを有効にする

SMS を介してユーザーをログインさせるには、まず Firebase プロジェクトで電話番号ログイン方法を有効にする必要があります。

  1. Firebase コンソールで [Authentication] セクションを開きます。
  2. [ログイン方法] ページで、[電話番号] のログイン方法を有効にします。

Firebase の電話番号ログイン リクエストの割り当ては多めになっており、ほとんどのアプリはこれで十分です。ただし、大量のユーザーを電話認証でログインさせる場合は、料金プランをアップグレードしなければならないことがあります。料金ページをご覧ください。

APN 通知の受信を開始する(iOS)

iOS で電話認証を使用するには、アプリが Firebase から APN 通知を受信する必要があります。端末でユーザーを初めて電話番号でログインさせると、Firebase Authentication から端末にサイレント プッシュ通知が送信され、電話番号のログイン リクエストがそのアプリから来ていることが確認されます。このため、電話番号のログインはシミュレータでは使用できません。

Firebase Authentication で APN 通知を有効にするには:

  1. Xcode で、プロジェクトのプッシュ通知を有効にします
  2. APN 証明書を Firebase にアップロードします。まだ APNs 証明書を用意していない場合は、APNs の SSL 証明書のプロビジョニング手順を確認してください。

    1. Firebase コンソールのプロジェクト内で歯車アイコンを選択し、[プロジェクトの設定]、[クラウド メッセージング] タブの順に選択します。

    2. 開発用証明書、本番用証明書、またはその両方の [証明書をアップロード] ボタンを選択します。少なくとも 1 つ選択する必要があります。

    3. 証明書ごとに .p12 ファイルを選択し、必要に応じてパスワードを入力します。この証明書のバンドル ID はアプリのバンドル ID と一致させてください。[保存] を選択します。

ユーザーの電話に確認コードを送信する

電話番号ログインを開始するには、ユーザーに電話番号の入力を求めるインターフェースを表示した後、PhoneAuthProvider::VerifyPhoneNumber を呼び出して、ユーザーのスマートフォンに認証コードを SMS で送信するよう Firebase にリクエストします。

  1. ユーザーの電話番号を取得します。

    法的要件はさまざまに異なりますが、電話番号ログインを使用する場合は確認用の SMS メッセージが送られること、それには標準料金がかかることをユーザーに知らせることをおすすめします。そうすることで、ユーザーもそのように心構えできます。

  2. PhoneAuthProvider::VerifyPhoneNumber を呼び出し、ユーザーの電話番号を渡します。
    class PhoneListener : public PhoneAuthProvider::Listener {
     public:
      ~PhoneListener() override {}
    
      void OnVerificationCompleted(Credential 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;
    PhoneAuthProvider& phone_provider = PhoneAuthProvider::GetInstance(auth);
    phone_provider->VerifyPhoneNumber(phone_number, kAutoVerifyTimeOut, null,
                                      &phone_listener);
    
    PhoneAuthProvider::VerifyPhoneNumber を呼び出すと、Firebase が次の処理を行います。
    • (iOS の場合)アプリにサイレント プッシュ通知を送信します。
    • 指定された電話番号に認証コードを含む SMS メッセージを送信し、検証 ID を補完機能に渡します。 ユーザーをログインさせるには、確認コードと確認 ID の両方が必要です。
  3. 確認 ID を保存し、アプリの読み込み時に復元します。これにより、ユーザーがログインフローを完了する前にアプリが終了した場合でも(たとえば SMS アプリへの切り替え時など)、有効な確認 ID を残すことができます。

    確認 ID は任意の方法で保持できます。クロスプラットフォーム C++ フレームワークを使用している場合は、アプリの終了と復元の通知を提供する必要があります。これらのイベントで、確認 ID の保存と復元をそれぞれ行うことができます。

VerifyPhoneNumber を呼び出したことによってリスナーで OnCodeSent が呼び出された場合、ユーザーが SMS メッセージを受信したら確認コードを入力するよう促します。

また、VerifyPhoneNumber を呼び出したことによって OnVerificationCompleted が返された場合は自動検証が成功しており、Credential が取得されます(使用方法は後で説明します)。

確認コードを使ってユーザーをログインさせる

ユーザーが SMS メッセージで受信した確認コードをアプリに入力したら、確認コードと確認 ID から Credential オブジェクトを作成し、そのオブジェクトを Auth::SignInWithCredential に渡して、ユーザーをログインさせます。

  1. ユーザーから確認コードを取得します。
  2. 確認コードと確認 ID から Credential オブジェクトを作成します。
    Credential 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.
            const 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 != nullptr) {
      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 Realtime Database と Cloud Storage のセキュリティ ルールでは、ログイン済みユーザーの一意のユーザー ID を auth 変数から取得し、それを使用してどのデータをユーザーからアクセス可能にするか制御できます。

既存のユーザー アカウントに認証プロバイダの認証情報をリンクすることで、ユーザーが複数の認証プロバイダを使用してアプリにログインできるようになります。

ユーザーのログアウトを行うには SignOut() を呼び出します。

auth->SignOut();

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。