Firebase AuthenticationとFirebaseUIを使ってWebアプリの認証機能をを作る

Firebase Authenticationを使うと、パスワード・電話番号・Google・Facebook・Twitter等を使った認証システムを簡単に作成できます。

FirebaseUIを使うことにより、見慣れたUIを提供できます。

今回作成したプログラムのソースコードはこちら。

Firebaseのプロジェクトを作成する

Firebaseコンソールにログインし、新しいプロジェクトを作成します。

プロジェクトの概要→プロジェクトを設定→マイアプリ→ウェブアプリにFirebaseを追加します。
このとき、Firebase Hostingも設定します。

プロジェクトの用意

最終的には、次のようになります。

public/ 公開フォルダー
  firebaseui.css
  index.html    サインイン画面
  success.html  ユーザー画面
src/    プログラムのソースコード
  index.js      サインイン画面のJavaScript
  success.js    ユーザー画面のJavaScript
package-lock.json
package.json
webpack.dev.js

ソースコードを配置するフォルダーを作成します。(ここではauth-testフォルダーとします)

$ mkdir auth-test

作成したフォルダーに移動します。

$ cd auth-test

ライブラリのインストール

package.jsonを作成します。

$ npm init

webpackをインストールします。

$ npm install webpack webpack-cli --save-dev

firebase npmパッケージをインストールします。

$ npm install --save firebase

firebaseui npmパッケージをインストールします。

$ npm install firebaseui --save

Firebase Hostinの設定

Fireebase Hostingを使用するために、Firebase CLIをインストールします。

npm install -g firebase-tools

ログインします。

$ firebase login

Firebaseプロジェクトの初期設定を行います。
Hostingをチェックして、セットアップします。

$ firebase init

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: auth-test-XXXX (auth-test)
i  Using project auth-test-XXXX (auth-test)

publicフォルダーが公開フォルダーになります。

ローカルで実行するときは、次のコマンドを実行します。

firebase serve

アプリをデプロイするときは、次のコマンドを実行します。

$ firebase deploy

http://localhost:5000にアクセスすると、開発しているサイトの動作を確認できます。

ファイル構成は次のようになります。

node_modules/
public/
firebase.json
package-lock.json
package.json

ビルド設定

ソースコードを配置するフォルダーを作成します。

mkdir src

srcフォルダー中のindex.jsとsuccess.jsをビルドして、publicフォルダー内に配置するようにします。

webpack.dev.jsを作成します。

module.exports = {
    mode: 'development',
    devtool: 'inline-source-map',
    entry: {
        index: './src/index.js',
        success: './src/success.js',
    },
    output: {
        path: __dirname + '/public',
        filename: '[name].js'
    }
};

package.jsonにscripts/buildを追加します。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config webpack.dev"
  },

srcフォルダーの中にindex.jsとsuccess.jsを作成します。

$ touch src/index.js
$ touch src/success.js

ビルドします。

$ npm run build

publicフォルダーにindex.jsとsuccess.jsが作成されます。

今後、jsファイルを編集したら、都度ビルドします。

サインインページの作成

public/index.htmlを編集します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="./firebaseui.css">
    <script src="./index.js" defer></script>
    <title>サインイン</title>
</head>
<body>
    <!-- Firebase UIによって書き換えられる -->
    <div id="firebaseui-auth-container"></div>
    <!-- ウィジェットが表示されたら非表示にする -->
    <div id="loader">loading...</div>
</body>
</html>

FirebaseUIをインストールします。

$ npm install firebaseui --save

FirebaseUIのスタイルシートをコピーします。

$ cp node_modules/firebaseui/dist/firebaseui.css public/

サインインページを表示する

ブラウザでhttp://localhost:5000/にアクセスすると、サインイン画面が表示されます。
(現在は、loading…と表示されます。)

Firebaseのメール/パスワード認証を有効にする

Firebaseコンソールのプロジェクトを開き、開発→Authenntication→Sign-in method→メール/パスワードを選択して、有効にします。

メール/パスワード認証画面を表示する

src/index.jsを編集します。

Firebase AuthenticationとFirebaseUIのライブラリをインポートします。

import * as firebase from "firebase/app";
import "firebase/auth";
import * as firebaseui from "firebaseui";

Firebaseコンソール(https://console.firebase.google.com/)のプロジェクト→プロジェクトの概要→プロジェクトを設定からコピーして貼り付けます。

const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "...",
    measurementId: "..."
};

Firebaseの初期化を初期化します。

firebase.initializeApp(firebaseConfig);

Firebase UIの設定を行います。
メール/パスワードによる認証を有効にします。

const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
        // メールプロバイダIDを追加
        {
            // FirebaseコンソールのAuthenticationセクションを開き、メール/パスワードによる認証を有効にする
            provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
        },
    ],
};

Firebase UIを初期化します。

const ui = new firebaseui.auth.AuthUI(firebase.auth());

Firebase UIを表示します。

ui.start('#firebaseui-auth-container', uiConfig);

プログラムをビルドします。

$ npm run build

ブラウザでhttp://localhost:8080/にアクセスすると、認証画面が表示されます。

ここまでのindex.jsは次のようになります。

import * as firebase from "firebase/app";
import "firebase/auth";
import * as firebaseui from "firebaseui";

// Firebaseコンソール(https://console.firebase.google.com/)のプロジェクト→プロジェクトの概要→プロジェクトを設定からコピー
const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "...",
    measurementId: "..."
};
// Firebaseの初期化
firebase.initializeApp(firebaseConfig);

// Firebase UIの設定
const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
        // メールプロバイダIDを追加
        {
            // FirebaseコンソールのAuthenticationセクションを開き、メール/パスワードによる認証を有効にする
            provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
        },
    ],
};

// Firebase UIの初期化
const ui = new firebaseui.auth.AuthUI(firebase.auth());

// Firebase UIを表示する
ui.start('#firebaseui-auth-container', uiConfig);

メールプロバイダの設定を変更します。
初期値ではユーザーの表示名の入力を求めます。この機能を無効にします。

// サポートするプロバイダ
signInOptions: [
    // メールプロバイダIDを追加
    {
        // FirebaseコンソールのAuthenticationセクションを開き、メール/パスワードによる認証を有効にする
        provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
        // [オプション]ユーザーに表示名の入力を求めるかどうか。初期値はtrue。
        requireDisplayName: false,
    },
],

スクリプトをビルドして、ブラウザをリロードすると、ユーザー名の入力欄が表示されなくなります。

Google認証を追加する

Googleのアカウントでもサインインできるようにします。

Firebaseコンソールのプロジェクトを開き、開発→Authenntication→Sign-in method→Googleを選択して、有効にします。

GoogleプロバイダIDを追加します。

const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
        // メールプロバイダIDを追加
        {
          ...
        },
        // GoogleプロバイダIDを追加
        {
            // FirebaseコンソールのAuthenticationセクションを開き、Googleによる認証を有効にする
            provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        },

スクリプトをビルドして、ブラウザをリロードすると、Google認証が追加されます。

電話認証を追加する

Firebaseコンソールのプロジェクトを開き、開発→Authenntication→Sign-in method→電話番号を選択して、有効にします。

電話番号プロバイダを追加します。

const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
        // メールプロバイダIDを追加
        {
          ...
        },
        // GoogleプロバイダIDを追加
        {
          ...
        },
        // 電話番号ログインを追加
        {
            // FirebaseコンソールのAuthenticationセクションを開き、電話番号ログインを有効にする
            provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
            // [オプション]reCAPTCHAの表示・非表示(デフォルトはnormal)
            // @see https://developers.google.com/recaptcha/docs/display
            recaptchaParameters: {
                type: 'image',
                size: 'invisible', // 'normal','invisible','compact'
                badge: 'bottomleft' // 'bottomleft','bottomright','inline'。sizeがinvisibleの場合に適用される
            }
        }

スクリプトをビルドして、ブラウザをリロードすると、Google認証が追加されます。

ウィジェットが表示されたときの処理

ウィジェットが表示されたとき、「loading…」を非表示にします。

const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
      ...
    ],
    callbacks: {
        /**
         * ウィジェットが表示されたとき
         */
        uiShown: function () {
            document.getElementById('loader').style.display = 'none';
        }
    },

サインインしたときに表示するページの設定

サインインしたら、success.htmlを表示するようにします。

const uiConfig = {
    // サポートするプロバイダ
    signInOptions: [
      ...
    ],
    callbacks: {
        /**
         * ユーザーが正常にサインインしたとき、自動的にリダイレクトするか開発者がハンドリングするかを決める
         * @param {firebaseui.auth.AuthResult} authResult 
         * @param {string|null} redirectUrl 
         * @returns {boolean} true:自動的にリダイレクトする false:開発者がハンドリングする
         */
        signInSuccessWithAuthResult: function (authResult, redirectUrl) {
            return true;
        },
        ...
    },
    // サインインしたときのリダイレクト先URL
    signInSuccessUrl: '/success.html',

ユーザー画面の作成

public/success.htmlを編集します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./success.js" defer></script>
    <title>サインインしました</title>
</head>
<body>
    <h1>サインインしました。</h1>
    <div>
        <button id="signOut">サインアウト</button>
    </div>
    <div>
        <a href="./index.html">サインインページ</a>
    </div>
</body>
</html>

src/success.jsを編集します。

初期化処理はサインインのときと同じです。

import * as firebase from "firebase/app";
import "firebase/auth";

// Firebaseコンソール(https://console.firebase.google.com/)のプロジェクト→プロジェクトの概要→プロジェクトを設定からコピー
const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "...",
    measurementId: "..."
};

// Firebaseの初期化
firebase.initializeApp(firebaseConfig);

サインインしているユーザー情報を取得します。

// 現在ログインしているユーザーを取得する
// ユーザーが初期化中などの中間状態ではない
firebase.auth().onAuthStateChanged(function (user) {
    if (user) {
        showUser(user);
    } else {
        console.log('ログインしていません。');
    }
});

/**
 * ユーザー情報を表示する
 * @param {*} user 
 */
function showUser(user) {
    console.log(user.displayName);
    console.log(user.email);
    console.log(user.photoURL);
    console.log(user.emailVerified);
    console.log(user.uid); // FirebaseプロジェクトでユニークなID
}

currentUserでも取得できますが、ユーザーが初期化中などの中間状態の可能性があります。

// 現在ログインしているユーザーを取得する
// ユーザーが初期化中などの中間状態の可能性がある
const user = firebase.auth().currentUser;
if (user) {
    console.log(user);
} else {
    console.log('ログインしていません。');
}

サインアウトの処理を追加します。

/**
 * サインアウト
 */
function signOut() {
    firebase.auth().signOut().then(function () {
        // Sign-out successful.
        console.log('サインアウトしました。');
    }).catch(function (error) {
        // An error happened.
        console.log(error);
    });
}

document.getElementById('signOut').addEventListener('click', function () {
    signOut();
});

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください