Flutter Firebase Authentication の導入【初心者向け】

Flutter

はじめに

アプリケーションでユーザーごとにデータを管理するには、認証機能が必要です。Firebase Authenticationを使うことで、Googleサインインメール・パスワード認証など、複数の方法で簡単に認証機能を追加することができます。この記事では、Firebase Authenticationを使ってFlutterアプリに認証機能を追加する方法を、初心者向けに解説します。


Firebase Authenticationのセットアップ

Firebaseプロジェクトの作成

  1. Firebaseコンソールhttps://console.firebase.google.com/)にアクセスし、新しいプロジェクトを作成します。
  2. プロジェクトを作成したら、Firebase Authenticationを有効化します。
  3. iOS アプリをプロジェクトに追加します。
    プロジェクト内で「Add app」ボタンをクリックし、「iOS」を選択します。
    アプリのバンドル ID(com.example.myapp など)を入力して登録します。
  4. GoogleService-Info.plist をダウンロードします。
    Firebase コンソールで iOS アプリの登録が完了すると、GoogleService-Info.plist ファイルをダウンロードできます。
  5. GoogleService-Info.plistを Flutter プロジェクトの ios/Runner フォルダに追加します。必ずxcode上から追加してください。

FlutterアプリへのFirebaseの追加

FlutterアプリにFirebaseを連携するために、次の手順を行います。

Firebase CLIをインストールしていない場合、ターミナルで以下のコマンドを実行してインストールします。

Bash
npm install -g firebase-tools

FirebaseプロジェクトとFlutterアプリをリンクさせるため、以下のコマンドを実行します。

Bash
firebase login
firebase init

firebase initの時の質問は一旦下記のように回答します。

Bash
? Which Firebase features do you want to set up for this directory? Press Space 
to select features, then Enter to confirm your choices. Functions: Configure a 
Cloud Functions directory and its files

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: flutter-app
(Flutter-app)

? What language would you like to use to write Cloud Functions? TypeScript
? Do you want to use ESLint to catch probable bugs and enforce style? Yes

pubspec.yamlに必要なパッケージを追加します。(バージョンは適宜変更してください)

YAML
dependencies:
  firebase_core: ^3.6.0
  firebase_auth: ^5.3.1

その後、以下のコマンドでパッケージをインストールします。

Bash
flutter pub get

Firebase Authenticationの実装

Firebaseの初期化

まず、Firebaseをアプリで使用できるように初期化します。main.dartに以下のコードを追加して、アプリ起動時にFirebaseを初期化します。

Dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AuthenticationWrapper(),
    );
  }
}

認証状態に応じた表示の切り替え

認証状態によって、ログイン画面ユーザーのTodoリスト画面を表示するようにします。以下のコードでは、認証状態に応じて画面を切り替える処理を実装しています。

Dart
class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else if (snapshot.hasData) {
          return MyHomePage(); // 認証されている場合
        } else {
          return LoginScreen(); // 未認証の場合
        }
      },
    );
  }
}

iosの設定

Podfileを編集し、下記コードを追加します。

Swift
platform :ios, '13.0'

メール・パスワード認証の実装

メールアドレスとパスワードを使用してサインアップ&サインインも簡単に実装できます。

Dart
class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  Future<void> _signIn() async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text.trim(),
      );
    } catch (e) {
      print('ログインに失敗しました: $e');
    }
  }

  Future<void> _signUp() async {
    try {
      await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text.trim(),
      );
    } catch (e) {
      print('サインアップに失敗しました: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('ログイン')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'メールアドレス'),
            ),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'パスワード'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _signIn,
              child: Text('ログイン'),
            ),
            ElevatedButton(
              onPressed: _signUp,
              child: Text('サインアップ'),
            ),
          ],
        ),
      ),
    );
  }
}

Googleサインインの導入

Googleサインイン導入方法についても解説していきます。

Firebase Authenticationの設定

Authenticationのログイン方法の設定画面にてGoogle認証を許可します。

google_sign_inパッケージの追加

Googleでサインインするには、google_sign_inパッケージも追加します。

YAML
dependencies:
  google_sign_in: ^5.4.0

URLスキームの追加

下記手順に従ってURLスキームの設定を行います。

  1. Xcodeでプロジェクトを開きます。
  2. Runnerプロジェクトのターゲット設定(左側のプロジェクトナビゲータから選択)に移動します。
  3. タブの中にあるInfoタブを開きます。
  4. URL Typesのセクションまでスクロールし、URL Schemesを追加します。
    • ここに、GoogleService-Info.plist内を参考に値を入力します。
      • IdentiferREVERSED_CLIENT_ID
      • URL_Schemes:com.googleusercontent.apps.xxxxxxxのような形式のもの

Googleサインイン機能の実装

Dart
import 'package:google_sign_in/google_sign_in.dart';

Future<void> _signInWithGoogle() async {
    try {
      // Googleサインイン
      final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
      final GoogleSignInAuthentication googleAuth = await googleUser!.authentication;

      // Firebase認証に必要なクレデンシャル
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );

      // サインインをFirebaseに登録
      await FirebaseAuth.instance.signInWithCredential(credential);
    } catch (e) {
      print('Googleサインインに失敗しました: $e');
    }
  }

今回のコード

今回の完成系のコードです。

Dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase Auth Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AuthenticationWrapper(),
    );
  }
}

class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else if (snapshot.hasData) {
          return MyHomePage(); // 認証されている場合
        } else {
          return LoginScreen(); // 未認証の場合
        }
      },
    );
  }
}

// ホーム画面(ログイン後)
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ホーム'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () async {
              await FirebaseAuth.instance.signOut();
            },
          ),
        ],
      ),
      body: Center(
        child: Text('ログイン済みです!'),
      ),
    );
  }
}

// ログイン画面
class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  Future<void> _signIn() async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text.trim(),
      );
    } catch (e) {
      print('ログインに失敗しました: $e');
    }
  }

  Future<void> _signUp() async {
    try {
      await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text.trim(),
      );
    } catch (e) {
      print('サインアップに失敗しました: $e');
    }
  }

  Future<void> _signInWithGoogle() async {
    try {
      // Googleサインイン
      final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
      final GoogleSignInAuthentication googleAuth = await googleUser!.authentication;

      // Firebase認証に必要なクレデンシャル
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );

      // サインインをFirebaseに登録
      await FirebaseAuth.instance.signInWithCredential(credential);
    } catch (e) {
      print('Googleサインインに失敗しました: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('ログイン')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'メールアドレス'),
            ),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'パスワード'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _signIn,
              child: Text('ログイン'),
            ),
            ElevatedButton(
              onPressed: _signUp,
              child: Text('サインアップ'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _signInWithGoogle, // Googleサインインボタン
              child: Text('Googleでサインイン'),
            ),
          ],
        ),
      ),
    );
  }
}

Firebase Authenticationのメリット

Firebase Authenticationは、複数の認証方法を提供しており、Googleサインインやメール・パスワード認証だけでなく、AppleやFacebookなどの他のプロバイダーとの連携も可能です。

  • セキュリティの向上:Firebaseが提供するセキュアな認証システムを利用できるため、セキュリティの心配が少なくなります。
  • 簡単な実装:複雑なサーバーサイドのコードを書くことなく、簡単に認証機能をアプリに追加できます。

まとめ

この記事では、Firebase AuthenticationをFlutterアプリに導入する方法を紹介しました。
アプリ開発を行う上で認証機能はほぼほぼ必須だと思うので、別記事で認証機能や暗号化について学びたいと思います。

この記事のポイント

  • Firebase Authenticationを使って、Googleサインインやメール・パスワード認証を導入。
  • 認証状態に応じて、画面を切り替える

この記事が参考になったら幸いです。

コメント

タイトルとURLをコピーしました