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

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

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

準備

  1. Firebase を iOS プロジェクトに追加します
  2. Podfile に次のポッドをインクルードします。
    pod 'Firebase/Auth'
    
  3. アプリを Firebase プロジェクトに接続していない場合は、Firebase コンソールで接続します。

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

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

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

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

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

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

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

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

サイレント通知の受信を開始する

電話番号認証を使用するには、アプリが Firebase からサイレント APN 通知を受信できる必要があります。ユーザーが端末で初めて電話番号を使用してログインすると、Firebase Authentication は端末にサイレント プッシュ通知を送信し、電話番号のログイン リクエストがアプリから来ていることを確認します(このため、電話番号のログインはシミュレータでは使用できません)。iOS 8.0 以降のサイレント通知は、明示的なユーザーの同意を必要としないため、ユーザーがアプリで APN 通知の受信を拒否することによる影響を受けません。したがって、Firebase 電話番号の認証を実装する際にプッシュ通知を受信するためのユーザー権限をアプリケーションで要求する必要はありません。

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

  1. Xcode で、プロジェクトのプッシュ通知を有効にします
  2. APNs 認証キーを Firebase にアップロードします。APNs 認証キーがまだない場合は、FCM での APNs の設定をご覧ください。

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

    2. [iOS アプリの設定] の下の [APNs 認証キー] で [アップロード] ボタンをクリックします。

    3. キーが保存されている場所に移動し、キーを選択して [開く] をクリックします。キーのキー ID(Apple Developer Member Center の [Certificates, Identifiers & Profiles] で確認できます)を追加し、[アップロード] をクリックします。

    APN 証明書を用意している場合には、証明書をアップロードできます。

実装入れ替えなしで通知を受け取る

Firebase Authentication はメソッドの実装入れ替えを使用して、自動的にアプリの APNs トークンを取得し、検証時に Firebase からアプリに送信されるサイレント プッシュ通知を処理します。

実装入れ替えを使用しない場合は、FirebaseAppDelegateProxyEnabled フラグをアプリの Info.plist ファイルに追加し、それを NO に設定することで入れ替えを無効化できます。このフラグを NO に設定すると、Firebase Cloud Messaging を含む他の Firebase 製品の実装入れ替えも無効になります。

実装入れ替えを無効にする場合は、明示的に APNs 端末トークンを渡し、通知を Firebase Authentication にプッシュする必要があります。

APNs 端末トークンを取得するには、application:didRegisterForRemoteNotificationsWithDeviceToken: メソッドを実装し、その中で端末トークンを FIRAuthsetAPNSToken:type: メソッドに渡します。

Swift

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  // Pass device token to auth
  Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenTypeProd)

  // Further handling of the device token if needed by the app
  // ...
}

Objective-C

- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  // Pass device token to auth.
  [[FIRAuth auth] setAPNSToken:deviceToken type:FIRAuthAPNSTokenTypeProd];
  // Further handling of the device token if needed by the app.
}

プッシュ通知を処理するには、application:didReceiveRemoteNotification:fetchCompletionHandler: メソッドで、FIRAuthcanHandleNotification: メソッドを呼び出して Firebase Authentication 関連の通知を確認します。

Swift

func application(_ application: UIApplication,
    didReceiveRemoteNotification notification: [AnyHashable : Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  if Auth.auth().canHandleNotification(notification) {
    completionHandler(UIBackgroundFetchResultNoData)
    return
  }
  // This notification is not auth related, developer should handle it.
}

Objective-C

- (void)application:(UIApplication *)application
    didReceiveRemoteNotification:(NSDictionary *)notification
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // Pass notification to auth and check if they can handle it.
  if ([[FIRAuth auth] canHandleNotification:notification]) {
    completionHandler(UIBackgroundFetchResultNoData);
    return;
  }
  // This notification is not auth related, developer should handle it.
}

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

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

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

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

  2. verifyPhoneNumber:completion: を呼び出し、ユーザーの電話番号を渡します。

    Swift

    PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
      if let error = error {
        self.showMessagePrompt(error.localizedDescription)
        return
      }
      // Sign in using the verificationID and the code sent to the user
      // ...
    }

    Objective-C

    [[FIRPhoneAuthProvider provider] verifyPhoneNumber:userInput
                                            UIDelegate:nil
                                            completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
      if (error) {
        [self showMessagePrompt:error.localizedDescription];
        return;
      }
      // Sign in using the verificationID and the code sent to the user
      // ...
    }];

    verifyPhoneNumber:completion: を呼び出すと、Firebase からアプリにサイレント プッシュ通知が送信されます。アプリが通知を受信すると、Firebase から認証コードを含む SMS メッセージが指定の電話番号に送信され、確認 ID が補完関数に渡されます。ユーザーをログインさせるには、確認コードと確認 ID の両方が必要です。

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

    Swift

     // Change language code to french.
     Auth.auth().languageCode = "fr";
    

    Objective-C

     // Change language code to french.
     [FIRAuth auth].languageCode = @"fr";
    
  3. 確認 ID を保存し、アプリの読み込み時に復元します。これにより、ユーザーがログインフローを完了する前にアプリが終了した場合でも(たとえば SMS アプリへの切り替え時など)、有効な確認 ID を残すことができます。

    確認 ID は任意の方法で保持できます。簡単な方法は、確認 ID を NSUserDefaults オブジェクトに保存することです。

    Swift

    UserDefaults.standard.set(verificationID, forKey: "authVerificationID")
    

    Objective-C

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:verificationID forKey:@"authVerificationID"];
    

    これで、保存された値を復元できます。

    Swift

    let verificationID = UserDefaults.standard.string(forKey: "authVerificationID")
    

    Objective-C

    NSString *verificationID = [defaults stringForKey:@"authVerificationID"];
    

verifyPhoneNumber:completion: への呼び出しが成功したら、SMS メッセージで受け取った確認コードを入力するようユーザーに要求できます。

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

ユーザーが SMS メッセージで受信した確認コードをアプリに入力したら、確認コードと確認 ID から FIRPhoneAuthCredential オブジェクトを作成し、そのオブジェクトを signInWithCredential:completion: に渡します。

  1. ユーザーから確認コードを取得します。
  2. 確認コードと確認 ID から FIRPhoneAuthCredential オブジェクトを作成します。

    Swift

    let credential = PhoneAuthProvider.provider().credential(
        withVerificationID: verificationID,
        verificationCode: verificationCode)

    Objective-C

    FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider]
        credentialWithVerificationID:verificationID
                    verificationCode:userInput];
  3. FIRPhoneAuthCredential オブジェクトを使用してユーザーをログインさせます。

    Swift

    Auth.auth().signIn(with: credential) { (user, error) in
      if let error = error {
        // ...
        return
      }
      // User is signed in
      // ...
    }
    }

    Objective-C

    [[FIRAuth auth] signInWithCredential:credential
                              completion:^(FIRUser *user, NSError *error) {
      if (error) {
        // ...
        return;
      }
      // User successfully signed in. Get user data from the FIRUser object
      // ...
    }];

次のステップ

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

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

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

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

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

Swift

    let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print ("Error signing out: %@", signOutError)
}
  

Objective-C

    NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

さまざまな認証エラーに対応できるようにエラー処理コードを追加することもできます。エラーの処理についての記事をご覧ください。

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

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