🔑

FlutterでFirebase Authenticationを使って認証機能を実装してみた

2023/08/24に公開

前回はFlutterとFirebaseを接続することができたので、今回はFirebaseの機能の一つであるFirebase Authenticationを使用してユーザーの認証機能を実装してみようと思います。

Firebase Authenticationとは

Authenticationとはユーザーを簡単かつ安全に認証する仕組みをFirebaseが提供してくれるサービスです。
メールアドレスや電話番号、Googleのアカウント等を使ったログイン機能を簡単に実装することができます。✨
https://firebase.google.com/docs/auth?hl=ja

Authentication機能を有効化しよう

Firebaseのプロジェクトを作成後(今回は前回作成したsampleAppsプロジェクトで行います)、Authentication機能を有効化してみましょう。
今回はとりあえず、メールとパスワードでのログイン機能を設定します。

  1. サイドナビのプロダクトのカテゴリ内にある「構築」→Authenticationを選択してください。

  2. 始めるボタンを押してください。

  3. ログイン方法の追加から「メール/パスワード」を選択してください。

  4. 「メール/パスワード」有効にするのトグルボタンをONにしてください。

    5.「メール/パスワード」が有効になりました。これでログイン機能を使えることができます✨

Flutter側の準備

無事Authenticationを使う準備が整いました。
次はFlutter側の準備を行いましょう。

  1. Flutterプロジェクトを作成しよう
    次のコマンドを実行するか、VScodeであれば、「command」+「shift」+「p」でcommand paletteを起動し、Flutter:New Projectでプロジェクトを作成しましょう。
  2. Flutterプロジェクトのルートから、次のコマンドを実行してfirebase_authをインストールします。
flutter pub add firebase_auth

firebase_authをインストールできなかった場合

自分が最初にインストールしようとした場合、このようなエラーが発生しました。

Because sample_apps depends on firebase_authv any which doesn't exist (could not find package firebase_authv at https://pub.dev), version solving failed.

解決方法

firebase_coreがインストールされていないことが原因でした。
次のコマンドでfirebase_coreをインストールしましょう。

flutter pub add firebase_core
  1. インストールが完了したら、次のコマンドを実行してFlutterアプリを再ビルドしましょう。
flutter run

ユーザー登録機能を実装してみよう

まずユーザーの登録をしないと認証することができないので実装してみましょう。

インストールしたプラグインをlib/main.dartにインポートします。

lib/main.dart
  import 'package:flutter/material.dart';
  import 'firebase_options.dart';
+ import 'package:firebase_auth/firebase_auth.dart';
+ import 'package:firebase_core/firebase_core.dart';

Firebaseの初期化を行いましょう。

lib/main.dart
- void main() {
-  runApp(const MyApp()):
- }
+  void main() async { WidgetsFlutterBinding.ensureInitialized();
+  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
+  runApp(const MyApp());
+ }

メールアドレスとパスワードの初期値を定義しましょう。

今回はメールアドレスとパスワードを設定し、それらをfirebase上で表示したいので、それぞれ定義しましょう。

lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
 //入力されたメールアドレスを入れるデータ
+  String newUserEmail = '';
 //入力されたパスワードを入れるデータ
+  String newUserPassword = '';
 // 登録・ログインに関する情報を表示するデータ
+  String infoText = '';

UIを作成しましょう

メールアドレスが入るテキストラベルとパスワードが入るテキストラベル、ユーザー登録をfirebaseに送るためのボタンを作成しましょう。

lib/main.dart
Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
        ),
        body: Center(
          child: Container(
            padding: EdgeInsets.all(8),
            child: Column(
              children: [
	       //Emailアドレスを入力するテキストラベルを作成する
                TextField(
                  decoration: InputDecoration(labelText: "Email"),
                  onChanged: () => {},
                ),
		//スペースを空ける
                const SizedBox(height: 8),
		//パスワードを入力するテキストラベルを作成する
                TextField(
                  decoration: InputDecoration(labelText: "Password"),
		  //パスワードが見えないように設定する
                  obscureText: true,
                  onChanged: () => {},
                  }),
                ),
		//スペースを空ける
                const SizedBox(height: 8),
		//このボタンを押すとfirebaseにユーザー情報が登録される
                ElevatedButton(
                  onPressed: (),
                  child: Text('Sign Up'),
                ),
              ],
            ),
          ),
        ));
  }

テキストを入力したときに画面が更新されるようにする

今の状態だとテキストに入力しても、テキストに文字が表示されません。
これはTextFormFieldのonChangeに何も設定がされていないため、テキストに文字を入力しても何も変更がされません。
文字が表示されるように次のように書き直しましょう。

lib/main.dart
//Emailアドレスを入力するテキストラベルを作成する
TextField(
decoration: InputDecoration(labelText: "Email"),
- onChanged: () => {},
+ onChanged:(String value) => 
+	setState((){
+	 newUserEmail = value;
+	}),
),
//スペースを空ける
const SizedBox(height: 8),
//パスワードを入力するテキストラベルを作成する
TextField(
decoration: InputDecoration(labelText: "Password"),
//パスワードが見えないように設定する
obscureText: true,
- onChanged: () => {},
+ onChanged:(String value) => 
+	setState((){
+	 newUserPassword = value;
+	}),
),

ここでsetStateを追加しているのは、前回の記事でも説明した通り、setState内でデータを更新しないと、データ自体は更新されますが、画面には再描画されないためです。
https://zenn.dev/ryofrontenginer/articles/9e8cca86cb97f1

Firebaseにユーザー情報を登録するボタンを実装する

メールアドレスとパスワードを入力するテキストラベルが完成したら、これらの情報をfirebaseに登録するためのボタンを実装しましょう。

lib/main.dart
//このボタンを押すとfirebaseにユーザー情報が登録される
ElevatedButton(
-  onPressed: (),
   //Firebaseと通信するのでasyncが必要
+  onPressed:() async {
+    //ユーザー登録が無事Firebaseに登録できた場合の処理
+     try {
+       final FirebaseAuth auth = FirebaseAuth.instance;
+       final UserCredential result = await auth.createUserWithEmailAndPassword(
+        email:newUserEmail,
+        password:newUserPassword,
+       );
+
+       final User user = result.user!;
+       setState((){
+         infoText = "ユーザー登録を完了しました。登録したメールアドレスは${user.email}です";
+       });
+     } catch(e) {
+       setState((){
+	 infoText = "ユーザー登録時にエラーが発生しました";
+       });
+     }
+   },
   child: Text('Sign Up'),
),

テストをしてみよう


無事登録することができました。
Firebaseに登録されているかも確認してみましょう。

こちらも無事に登録されていますね😌

ログイン機能を実装してみよう

ユーザー登録機能が実装できたので、ログイン機能も実装してみましょう。

lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
   String newUserEmail = '';
   String newUserPassword = '';
+  String loginUserEmail = '';
+  String loginUserPassword = '';
+  String infoText = '';

  
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
        ),
        body: Center(
          child: Container(
            padding: EdgeInsets.all(8),
            child: Column(
              children: [
                Text('SignUp'),
                TextField(
                  decoration: InputDecoration(labelText: "Email"),
                  onChanged: (String value) => setState(() {
                    newUserEmail = value;
                  }),
                ),
                const SizedBox(height: 8),
                TextField(
                  decoration: InputDecoration(labelText: "Password"),
                  obscureText: true,
                  onChanged: (String value) => setState(() {
                    newUserPassword = value;
                  }),
                ),
                const SizedBox(height: 8),
                ElevatedButton(
                  onPressed: () async {
                    try {
                      final FirebaseAuth auth = FirebaseAuth.instance;
                      final UserCredential result = await auth.createUserWithEmailAndPassword(
                        email: newUserEmail,
                        password: newUserPassword,
                      );

                      final User user = result.user!;
                      setState(() {
                        infoText = "ユーザー登録を完了しました。登録したメールアドレスは${user.email}です";
                      });
                    } catch (e) {
                      setState(() {
                        infoText = 'ユーザー登録時にエラーが発生しました';
                      });
                    }
                  },
                  child: Text('Sign Up'),
                ),
                const SizedBox(height: 8),
                //ログイン実装
+             Text("Login"),
+             TextField(
+               decoration: InputDecoration(labelText: "Email"),
+                onChanged: (String value) => setState(() {
+                  loginUserEmail = value;
+                }),
+             ),
+              const SizedBox(height: 8),
+              TextField(
+                decoration: InputDecoration(labelText: "Password"),
+                obscureText: true,
+                onChanged: (String value) => setState(() {
+                  loginUserPassword = value;
+                }),
+              ),
+              const SizedBox(height: 8),
+              ElevatedButton(
+                onPressed: () async {
+                  try {
+                    final FirebaseAuth auth = FirebaseAuth.instance;
+                    final UserCredential result = await auth.signInWithEmailAndPassword(
+                      email: loginUserEmail,
+                        password: loginUserPassword,
+                      );
+
+                      final User user = result.user!;
+                      setState(() {
+                        infoText = "ログインに成功しました。ログインメールアドレスは${user.email}です";
+                      });
+                    } catch (e) {
+                      setState(() {
+                        infoText = 'ログイン時にエラーが発生しました';
+                      });
+                    }
+                  },
+                  child: Text('Login'),
+                ),
+                const SizedBox(height: 8),
+                Text(infoText),
              ],
            ),
          ),
        ));
  }
}

最後に

Firebase Authenticationを使用することで、簡単にサインアップ機能とログイン機能を実装することができます。他にもGoogleアカウントやTwitterアカウントでのログイン機能も実装することができるので、用途に応じて使用してもらえればと思います。

Discussion