ログイン新規登録

Qiitaにログインして、便利な機能を使ってみませんか?

あなたにマッチした記事をお届けします

便利な情報をあとから読み返せます

13
2

【Firebase初心者向け】SMS認証でアカウント乗っ取りを防げ!【Flutter初心者は🙅‍♀️】

最終更新日 投稿日 2023年12月13日

※この記事は、筑波大学情報科学類とN/S高等学校のコラボプロジェクト筑波NSミライラボ Advent Calendar 2023の12月14日の記事です。

こんにちは、N高1年の青柳世成です。
今回はFlutterを使ってSMS認証を作っていきたいと思います。
*今回はAndroid版しか作りません。

この記事のターゲット

・Flutterはある程度分かるけどFirebaseについての知識がない!
・Firebaseを何から始めればいいのかわからない🧐
という方向けにちょいムズイレベルのSMS認証から入っていただければと思い作りました!

SMS認証とは

SMS認証とは、スマホやガラケーなどの携帯電話宛に送信されたSMSに記載のある確認コードを入力してログインする仕組みです。

SMS認証を導入することで、セキュリティ対策を大幅に強化できます。基本的に本人以外がデバイスを所持していることは少ないため、悪意のある不正アクセスを防ぎやすい傾向にあります。
また、SMS認証は電話番号にメッセージを送信する方法であるため、第三者にパスワードが漏れるといった心配もありません。
端末取られたらどうしようもなくね?って思ってる人は🤫

用意するもの

Android Studio, FlutterSDK, Googleアカウント, Firebaseプロジェクト
(多分これで全部だと思うけど多すぎて忘れてるかも...)

Firebaseプロジェクトの作成

リンクを開いたら「コンソールへ移動」ボタンを押してください。
コンソールへ移動
このような画面に移るはずです。
「プロジェクトを追加」を押して、手順に沿ってプロジェクトを作成してください。
Firebase コンソール
Flutterを選択してください。
Flutter
必要なものを入れていきます。
次のセクションへGO!!
※Flutterを押したらその画面のままタブを置いといてください、この後使います。

前準備

Node.jsがインストールされている前提で話を進めていきます。
まだインストールしていない方はこちらから道なりにインストールしてください。

Firebase CLI

Terminalを開き、次のコマンドを実行してください。

npm install -g firebase-tools

このコマンドはFirebase CLIをインストールするコマンドです。
Googleアカウントにログインする必要があるので、次のコマンドでログインします。

firebase login

ログインできたら、Firebaseプロジェクトを一覧表示し、CLIが正しくインストールされていてアカウントにアクセスしていることをテストします。

firebase projects:list

先ほど作成したFirebaseプロジェクトが表示されていたらOKです!

FlutterFire

※この手順の前にAndroid Studioでいつも通りプロジェクトを作ってください。
Android Studioプロジェクトからターミナルを開き、以下のコマンドを入力してください。

dart pub global activate flutterfire_cli

実行後

Activated flutterfire_cli 0.2.7.

と表示されたら以下のボタンを押して二個目のコマンドをコピーします。
FlutterFire CLI
コピーしたコマンドをターミナルに貼り付けます。

Which platforms should your configuration support (use arrow keys & space to select)?

という表示が出たら、どのプラットフォームで作りたいか?ということなので、Androidだけを選びます。

Android以外のチェックを外します。矢印キーで上下、スペースキーでチェックを切り替えることができます。
Androidのみにしたら、Enterキーで確定します。

次に

The files android/build.gradle & android/app/build.gradle will be updated to apply Firebase configuration and gradle build plugins. Do you want to continue?

と表示されるので、「y」キーを押してEnterで次に進んでください。

Learn more about using this file and next steps from the documentation:
 > https://firebase.google.com/docs/flutter/setup

と表示されたら完了です!

Android用のデバッグキー

Android Studioでいつも通りプロジェクトを作成し、プロジェクトを開いてターミナルで下記のコマンドを実行してください。

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

※このコマンドがJavaのエラーで使えない方は以下の記事を参考にしてください。
https://zenn.dev/satokazur222/articles/66568417b291d8

実行すると、SHA1キーが生成されます。
出力の以下の部分をコピーします。

Certificate fingerprints:
         SHA1: ここ!

コピーできたら、Firebaseプロジェクトの設定から以下の部分にキーを追加します。
SHA 証明書フィンガープリント

これで、準備が完了しました。
依存関係のインストールをしていきます!

依存関係のインストール

Android Studioでプロジェクトを作成し、以下のコマンドをターミナルに打ち、依存関係をインストールします。

- flutter pub add firebase_core
- flutter pub add firebase_auth

Authencation設定

Firebaseプロジェクト内メニューからAuthencationを探し、「始める」を押すことで認証方法の選択画面に飛びますので、電話番号を選択してください。

全ての準備が完了しました!
やっとコード書ける...

実装

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

このコード全体の流れは、Flutterフレームワークを初期化し、Firebaseを初期化し、最終的にアプリケーションを開始するというものです。

void main() async {

エントリーポイントであるmain関数が定義されています。この関数はプログラムの開始点です。

WidgetsFlutterBinding.ensureInitialized();

ensureInitializedは、Flutterフレームワークが初期化されたことを確認します。

await Firebase.initializeApp();

Firebase.initializeApp()は、Firebaseの初期化を行います。この呼び出しは非同期処理であり、awaitが使用されています。Firebaseを使用する前に、Firebaseを初期化する必要があります。

runApp(MyApp());

runApp関数は、Flutterアプリを開始します。引数にはMyApp()というウィジェットが渡されています。MyAppはアプリケーションのメインウィジェットです。

※ここから下は全て

final FirebaseAuth _auth = FirebaseAuth.instance;

を定義してください。

_authはFirebase Authenticationを使用するためのFirebaseAuthのインスタンスです。これは、Firebaseアプリ全体で共有されるため、finalキーワードで宣言しています。

アカウント登録

Future<User?> signUpWithPhoneNumber(String phoneNumber) async {
    try {
      await _auth.verifyPhoneNumber(
        phoneNumber: phoneNumber,
        verificationCompleted: (PhoneAuthCredential credential) async {
          // 認証が完了した場合
          UserCredential authResult = await _auth.signInWithCredential(credential);
          return authResult.user;
        },
        verificationFailed: (FirebaseAuthException e) {
          // 認証が失敗した場合
          print("認証失敗: ${e.message}");
        },
        codeSent: (String verificationId, int? resendToken) {
          // SMSコードが送信された場合
          // ここで認証コードの入力UIを表示するなど...
          print("コード送信済み。認証ID: $verificationId");
        },
        codeAutoRetrievalTimeout: (String verificationId) {
          // 認証がタイムアウトした場合
          print("コード自動取得のタイムアウト。認証ID: $verificationId");
        },
      );
    } catch (e) {
      print("電話番号認証中のエラー: $e");
      return null;
    }
  }

Future<User?> signUpWithPhoneNumber(String phoneNumber) async {

signUpWithPhoneNumber関数は、電話番号を使用したユーザー登録を行います。戻り値の型はFutureであり、非同期関数であることを示すasyncが付いています。

try {

関数の実際の処理が始まります。エラーが発生する可能性がある処理をtry-catchで囲みます。

await _auth.verifyPhoneNumber(

_authのverifyPhoneNumberを呼び出して、電話番号を認証します。これにより、ユーザーにSMSコードが送信され、電話番号の確認が行われます。

verificationCompleted: (PhoneAuthCredential credential) async {

認証が完了した場合の関数。認証が完了すると、渡されたcredentialを使用してユーザーをサインインします。

verificationFailed: (FirebaseAuthException e) {

認証が失敗した場合の関数。エラーメッセージがコンソールに表示されます。

codeSent: (String verificationId, int? resendToken) {

SMSコードが送信された場合の関数。認証コードの送信が成功したことをログに表示します。

codeAutoRetrievalTimeout: (String verificationId) {

認証が自動的にタイムアウトした場合の関数。タイムアウトが発生したことをログに表示します。

} catch (e) {

try内で発生した例外をキャッチし、エラーメッセージをログに表示します。

return null;

電話番号認証中にエラーが発生した場合、nullを返します。

ログイン

Future<User?> signInWithPhoneNumber(String verificationId, String smsCode) async {
    try {
      PhoneAuthCredential credential = PhoneAuthProvider.credential(
        verificationId: verificationId,
        smsCode: smsCode,
      );
      UserCredential authResult = await _auth.signInWithCredential(credential);
      return authResult.user;
    } catch (e) {
      print("電話番号サインイン中のエラー: $e");
      return null;
    }
  }

Future<User?> signInWithPhoneNumber(String verificationId, String smsCode) async {

signInWithPhoneNumber関数は、Firebase Authenticationを使用して電話番号でのサインインを行います。引数には認証ID(verificationId)とSMSコード(smsCode)が渡されます。戻り値の型はFutureであり、非同期関数であることを示すasyncが付いています。

try {

関数の処理が始まります。エラーが発生する可能性がある処理をtry-catchで囲みます。

PhoneAuthCredential credential = PhoneAuthProvider.credential(

PhoneAuthProvider.credentialメソッドを使用して、電話番号認証のための情報を生成します。これにはverificationId(認証ID)とsmsCode(SMSコード)が必要です。

UserCredential authResult = await _auth.signInWithCredential(credential);

生成された情報を使用して、_authを介してサインインを試行します。サインインが成功すると、UserCredentialオブジェクトが得られます。

return authResult.user;

サインインが成功した場合、UserCredentialからUserを取得し、それを戻り値として返します。

} catch (e) {

try内で発生した例外をキャッチし、エラーメッセージをログに表示します。

print("電話番号サインイン中のエラー: $e");

キャッチしたエラーをログに表示します。

return null;

サインイン中にエラーが発生した場合、nullを返します。

ログアウト

Future<void> signOut() async {
    await _auth.signOut();
  }

Future<void> signOut() async {

signOut関数は、非同期関数であり、引数も戻り値もないことを示すFuture型です。サインアウト処理を行います。

await _auth.signOut();

_authのsignOutを呼び出して、現在のユーザーをサインアウトします。この処理は非同期であるため、awaitを使用して待機します。

あとがき

今回の記事では、Flutterを使用してSMS認証を実装する手順を紹介しました。Firebaseを利用して、セキュリティを強化した認証機能を実装することができます。

初めてFirebaseを使用する方や、SMS認証に興味がある方にとって、ちょうどいい難易度の内容だったでしょうか。

また、記事内で使用したリンクやコマンドがうまく動作しない場合は、最新の情報を確認してください。技術は常に進化していますので、変更があるかもしれません。

FlutterやFirebaseを使った開発は、ユーザーエクスペリエンス向上に貢献する強力なツールです。今後もさまざまな機能やアプリケーションを開発していく中で、新たな発見や工夫をしていただければ嬉しいです。

お疲れ様でした!どうぞ楽しいFlutter開発をお過ごしください。

13
2
0

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
  3. ダークテーマを利用できます
ログインすると使える機能について

コメント

この記事にコメントはありません。

いいね以上の気持ちはコメントで

Qiita Conference 2024 4月17日(水)~19(金)開催!

Qiita Conferenceは、Qiita最大規模のテックカンファレンスです!

基調講演ゲスト(敬称略)

牛尾剛、 市谷聡啓、 けんすう、 ゆる言語学ラジオ、 田中邦裕、小城久美子、 飯沼亜紀

13
2

ログインして続ける

ソーシャルアカウントでログイン・新規登録

メールアドレスでログイン・新規登録