Firebase Authentication Googleサインイン

対話システムを構築する際に、個人認証は必須となります。そこで、今回はFirebaseのAuthentcation機能を使って、ログイン機能を作ってみたいと思います。

Firebaseの認証機能では、様々な認証が用意されています。メールアドレスとパスワードを使ってユーザ登録とログインをする方法がよく使われています。しかし、新たにユーザ登録するのは面倒かもしれません。今ではほとんどの方が、GoogleもしくはAppleのIDをお持ちだと思いますので、まずは、Google認証にチャレンジします。以下は、基本的にWebアプリを前提としてます。

公式はこちらのサイト

Firebaseコンソールでの設定

Googleプロバイダの追加

Firebaseコンソールにログインして、サイドメニューの「構築」から「Authentication」を選択します。

Sign-in methodタグの「新しいプロバイダ」ボタンをクリックしてGoogleを追加します。

Googleプロバイダを有効にしたら、ウェブSDK構成を開いて、ウェブクライアントIDを確認してメモしておきます。

承認済みドメインの追加

Settingsタブで「承認済みドメイン」を追加します。localhost と、Firebase のHositingサイトは自動で設定されていますので、必要に応じて追加しておきます。

firebaseコンソールでの設定は、以上の2ヶ所です。

Flutter アプリ側の設定

こちらの記事を参考にfirebase SDKをインストールして初期化しておきます。

flutterfire_cliを使ってconfigureすると、lib/firebase_options.dartが生成されます。ここには、Firebaseをinitializeするときのオプションが定義されています。

プラグインをインストールします。

flutter pub add firebase_core
flutter pub add firebase_auth

iOS,Androidのアプリの場合には、google_sign_in プラグインもインストールしますが、webアプリの場合には不要です。

コードにプラグインをインポート

import 'package:firebase_auth/firebase_auth.core';
import 'package:firebase_auth/firebase_auth.dart';

Google認証サンプルコード

Google認証の最低限のサンプルコードは、以下の通りです。 画面上のLoginをクリックすると、認証用のpopupが表示されます。認証が成功すれば、Chat画面(仮)に遷移し、 userのdisplayNameが表示されます。 Loginしたユーザは、FirebaseのAuthenticationのusersからログイン日時などが確認できます。

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'src/chat.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const LoginPage(title: 'Flutter Demo Home Page'),
    );
  }
}

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<LoginPage> createState() => _loginPageState();
}

class _loginPageState extends State<LoginPage> {
  // Googleアカウントの表示名
  String infoText = '';

 // 公式ページのコードをそのままコピー
  Future<UserCredential> signInWithGooglePopup() async {
    // Create a new provider
    GoogleAuthProvider googleProvider = GoogleAuthProvider();
    googleProvider
        .addScope('https://www.googleapis.com/auth/contacts.readonly');
    googleProvider.setCustomParameters({'login_hint': 'user@example.com'});
    return await FirebaseAuth.instance.signInWithPopup(googleProvider);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
        TextButton(
          onPressed: () async {
            try {
              await signInWithGooglePopup();
              final User? user = FirebaseAuth.instance.currentUser;
              if (user != null) {
                await Navigator.of(context).pushReplacement(
                  MaterialPageRoute(builder: (context) {
                    return ChatPage(user);
                  }),
                );
              }
            } catch (e) {
              setState(() {
                infoText = 'Loginに失敗しました:${e.toString()}';
              });
            }
          },
          child: const Text(
            'login',
            style: TextStyle(fontSize: 50),
          ),
        ),
        Text(infoText), // loginされなかった時のメッセージを表示
      ]),
    ));
  }
}
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'main.dart';

// チャット画面用Widget
class ChatPage extends StatelessWidget {
  ChatPage(this.user);
  final User user;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('チャット'),
        actions: <Widget>[
          IconButton(
            icon: const Icon(Icons.logout),
            onPressed: () async {
              await FirebaseAuth.instance.signOut();
              // ログイン画面に遷移+チャット画面を破棄
              await Navigator.of(context).pushReplacement(
                MaterialPageRoute(builder: (context) {
                  return LoginPage(title: 'Login Page');
                }),
              );
            },
          ),
        ],
      ),
      body: Center(
        // ユーザー情報を表示
        child: Text('ログイン情報:${user.displayName}'),
      ),
    );
  }
}

localhostでテストする場合には、承認済みのドメインとポート番号を合わせる必要があります。

承認済みドメインが https://localhost:5000の場合は、

flutter run --web-port 5000

と、ポート番号を指定して起動する必要があります。