Android で電話番号を使用して Firebase 認証を行う

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

電話番号ログインをアプリに追加する最も簡単な方法は、FirebaseUI を使用することです。このライブラリには、電話番号ログインのほか、パスワードに基づくログインやフェデレーション ログインのログインフローを実装するドロップイン式のログイン ウィジェットが含まれています。このドキュメントでは、Firebase SDK を使用して電話番号ログインフローを実装する方法について説明します。

準備

  1. Firebase を Android プロジェクトに追加します
  2. Firebase Authentication の依存関係をアプリレベルの build.gradle ファイルに追加します。
    compile 'com.google.firebase:firebase-auth:11.8.0'
  3. アプリを Firebase プロジェクトに接続していない場合は、Firebase コンソールで接続します。
  4. アプリの SHA-1 ハッシュが Firebase コンソールで設定されていない場合は、設定します。アプリの SHA-1 ハッシュの検索方法について詳しくは、クライアントの認証をご覧ください。

また、電話番号ログインを行うには物理デバイスが必要です。エミュレータでは機能しません。

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

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

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

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

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

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

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

ユーザーのスマートフォンに確認コードを送信する

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

次に、電話番号を PhoneAuthProvider.verifyPhoneNumber メソッドに渡して、ユーザーの電話番号を確認するよう Firebase にリクエストします。次に例を示します。

PhoneAuthProvider.getInstance().verifyPhoneNumber(
        phoneNumber,        // Phone number to verify
        60,                 // Timeout duration
        TimeUnit.SECONDS,   // Unit of timeout
        this,               // Activity (for callback binding)
        mCallbacks);        // OnVerificationStateChangedCallbacks

verifyPhoneNumber メソッドはリエントラントです。たとえば、アクティビティの onStart メソッドなどで複数回呼び出された場合でも、元のリクエストがタイムアウトしていなければ、verifyPhoneNumber メソッドから 2 番目の SMS は送信されません。

この動作を利用して、ユーザーがログインする前にアプリが終了した場合でも(たとえばユーザーが SMS のアプリを使用している間など)、電話番号のログイン プロセスを再開できます。verifyPhoneNumber を呼び出した後で、確認中であることを示すフラグを設定します。次に、アクティビティの onSaveInstanceState メソッドでフラグを保存したら、フラグを onRestoreInstanceState で復元します。最後に、アクティビティの onStart メソッドで、確認がすでに実行中であるかどうかをチェックし、実行中であれば verifyPhoneNumber を再度呼び出します。確認が完了または失敗した場合は、必ずフラグをクリアしてください(詳しくは確認のコールバックをご覧ください)。

画面の回転、アクティビティのその他のインスタンスの再起動を簡単に処理できるよう、アクティビティを verifyPhoneNumber メソッドに渡します。アクティビティが停止するとコールバックは自動的に接続解除されるので、UI 遷移コードをコールバック メソッドに自由に書き込むことができます。

Firebase によって送信された SMS メッセージは、Auth インスタンスの setLanguageCode メソッドを使用して認証言語を指定することによってローカライズすることもできます。

auth.setLanguageCode("fr");
// To apply the default app language instead of explicitly setting it.
// auth.useAppLanguage();

PhoneAuthProvider.verifyPhoneNumber を呼び出すときは、リクエストの結果を処理するコールバック関数の実装を含む OnVerificationStateChangedCallbacks のインスタンスも指定する必要があります。以下に例を示します。

mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    @Override
    public void onVerificationCompleted(PhoneAuthCredential credential) {
        // This callback will be invoked in two situations:
        // 1 - Instant verification. In some cases the phone number can be instantly
        //     verified without needing to send or enter a verification code.
        // 2 - Auto-retrieval. On some devices Google Play services can automatically
        //     detect the incoming verification SMS and perform verification without
        //     user action.
        Log.d(TAG, "onVerificationCompleted:" + credential);

        signInWithPhoneAuthCredential(credential);
    }

    @Override
    public void onVerificationFailed(FirebaseException e) {
        // This callback is invoked in an invalid request for verification is made,
        // for instance if the the phone number format is not valid.
        Log.w(TAG, "onVerificationFailed", e);

        if (e instanceof FirebaseAuthInvalidCredentialsException) {
            // Invalid request
            // ...
        } else if (e instanceof FirebaseTooManyRequestsException) {
            // The SMS quota for the project has been exceeded
            // ...
        }

        // Show a message and update the UI
        // ...
    }

    @Override
    public void onCodeSent(String verificationId,
                           PhoneAuthProvider.ForceResendingToken token) {
        // The SMS verification code has been sent to the provided phone number, we
        // now need to ask the user to enter the code and then construct a credential
        // by combining the code with a verification ID.
        Log.d(TAG, "onCodeSent:" + verificationId);

        // Save verification ID and resending token so we can use them later
        mVerificationId = verificationId;
        mResendToken = token;

        // ...
    }
};

確認のコールバック

ほとんどのアプリにおいて、onVerificationCompletedonVerificationFailed、および onCodeSent のコールバックを実装することになります。アプリの要件によっては、onCodeAutoRetrievalTimeOut を実装する場合もあります。

onVerificationCompleted(PhoneAuthCredential)

このメソッドは、次の 2 つの状況で呼び出されます。

  • 即時確認: 確認コードを送信または入力することなく電話番号を即座に確認することができる場合があります。
  • 自動取得: 一部の端末では、受信した確認 SMS を Google Play サービスが自動的に検出して確認を実行することができます。この場合、ユーザーの操作は不要です(この機能は、一部の携帯通信会社では使用できない場合があります)。
いずれの場合も、ユーザーの電話番号が正常に確認されたら、コールバックに渡された PhoneAuthCredential オブジェクトを使用してユーザーのログインを行うことができます。

onVerificationFailed(FirebaseException)

このメソッドは、無効な確認リクエスト(無効な電話番号や確認コードが指定されたリクエストなど)に対するレスポンスとして呼び出されます。

onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken)

省略可。このメソッドは、確認コードが指定の電話番号に SMS で送信された後で呼び出されます。

このメソッドが呼び出されると、ほとんどのアプリでは、SMS メッセージに示されている確認コードの入力をユーザーに要求する UI が表示されます(これと同時に、バックグラウンドで自動確認が処理されている場合があります)。次に、ユーザーが確認コードを入力したら、この確認コードとメソッドに渡された確認 ID を使用して PhoneAuthCredential オブジェクトを作成し、ユーザーのログインを行うことができます。ただし、アプリによっては、onCodeAutoRetrievalTimeOut が呼び出されるのを待ってから確認コードの UI を表示する場合がありますが、これは推奨されません。

onCodeAutoRetrievalTimeOut(String verificationId)

省略可。このメソッドは、onVerificationCompleted がトリガーされずに、verifyPhoneNumber に指定されているタイムアウト時間が経過した場合に呼び出されます。SIM カードが挿入されていない端末では、SMS の自動取得を実行できないため、このメソッドが直ちに呼び出されます。

一部のアプリでは、自動確認時間がタイムアウトになるまでユーザーの入力はブロックされ、その後で SMS メッセージに示されている確認コードの入力をユーザーに要求する UI が表示されますが、これは推奨されません。

PhoneAuthCredential オブジェクトを作成する

Firebase からユーザーのスマートフォンに送信された確認コードをユーザーが入力したら、確認コードと onCodeSent コールバックまたは onCodeAutoRetrievalTimeOut コールバックに渡された確認 ID を使用して、PhoneAuthCredential オブジェクトを作成します(onVerificationCompleted が呼び出された場合は PhoneAuthCredential オブジェクトが直接取得されるため、この手順はスキップできます)。

PhoneAuthCredential オブジェクトを作成するには、PhoneAuthProvider.getCredential を呼び出します。

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);

ユーザーのログインを行う

PhoneAuthCredential オブジェクトを取得したら、onVerificationCompleted コールバックを使用するか、または PhoneAuthProvider.getCredential を呼び出して、PhoneAuthCredential オブジェクトを FirebaseAuth.signInWithCredential に渡しログインフローを完了します。

private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
    mAuth.signInWithCredential(credential)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "signInWithCredential:success");

                        FirebaseUser user = task.getResult().getUser();
                        // ...
                    } else {
                        // Sign in failed, display a message and update the UI
                        Log.w(TAG, "signInWithCredential:failure", task.getException());
                        if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                            // The verification code entered was invalid
                        }
                    }
                }
            });
}

次のステップ

ユーザーが初めてログインすると、新しいユーザー アカウントが作成され、ユーザーがログインに使用した認証情報(ユーザー名とパスワード、電話番号、または認証プロバイダ情報)にアカウントがリンクされます。この新しいアカウントは Firebase プロジェクトの一部として保存され、ユーザーのログイン方法にかかわらず、プロジェクトのすべてのアプリでユーザーを識別するために使用できます。

  • アプリでは FirebaseUser オブジェクトからユーザーの基本的なプロフィール情報を取得できます。ユーザーの管理についての記事をご覧ください。

  • Firebase Realtime Database と Cloud Storage のセキュリティ ルールでは、ログイン済みユーザーの一意のユーザー ID を auth 変数から取得し、それを使用してユーザーがアクセスできるデータを制御できます。

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

ユーザーをログアウトするには signOut を呼び出します。

FirebaseAuth.getInstance().signOut();

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

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