【React/TypeScript】Firebaseでメール認証とGoogle認証を実装する

本記事ではReact(TypeScript)アプリにFirebaseを使った認証機能を組み込む方法を紹介します。認証はメールアドレスとパスワードを使った認証とGoogleアカウントを使った認証の2種類で行えるようにしています。見栄えは多少よくしてレスポンシブ対応も軽く行っています。なおコンポーネント間のユーザー情報の共有は、Reduxは使わずContextとHooksで行っています。

ソースコードはGitHubで公開していますので、よかったらご利用ください。

GitHub

React/TypeScriptによるFirebase認証アプリ. Contribute to ganeo/react-…

完成イメージ

トップページ(パス: /)では2種類のログイン(メールアドレス/パスワードおよびGoogle)とメールアドレス/パスワード認証用のサインアップができます。ログインするとホームページ(パス: /home)に遷移します(ログイン済みだとトップページを開こうとしてもホームページにとびます)。ホームページはログインしていないと入れません。

トップページ(パス: /)
完成イメージ1

 

ログインすると表示されるホームページ(パス: /home)
完成イメージ2

Firebase側の設定

プロジェクトの作成

Firebaseにログインしてプロジェクトを作成します。プロジェクト名は後ほど作成するReactのアプリ名と揃えて「react-firebase-auth-sample」としておきます。Googleアナリティクスは無効にしてさくっとプロジェクトを作成します。

Firebaseプロジェクト作成

認証機能の有効化

作成したプロジェクトの「Authentication」メニューから「Sign-in method」タブを選択して「メール/パスワード」と「Google」の認証を有効にします。

firebase_auth_mail
「メール/パスワード」認証の有効化
firebase_auth_google
「Google」認証の有効化

Webアプリの追加

プロジェクトのホーム画面で「</>」ボタンをクリックしてWebアプリを追加します。アプリを追加するとFirebaseに接続するためのAPIキーなどを取得できます。この情報は次に作成するReactアプリで利用します。

firebase_home

firebase_add_app

APIkey

React/TypeScriptの実装

React/TypeScriptアプリの雛形を作成

TypeScript用Reactアプリをcreate react appコマンドで作成します。

yarn create react-app react-firebase-auth-sample –template typescript
※青字イタリック体はアプリ名です。

利用するパッケージのインストール

FirebaseのSDKとルーティング用のパッケージをインストールします。上記で作成したReactアプリのルートディレクトリで次のコマンドを実行します。

yarn add firebase react-router-dom @types/react-router-dom

ソースコードの編集

以下では認証に関わる部分だけを抜粋して説明しています。ちなみに追加したCSSはデフォルトで存在するApp.cssを上書きして全てここに記述しています。

Firebase接続用キーを環境変数として設定

Firebase接続用キーをソースコードに直接書くのは流出の危険性が増すので、Reactの雛形アプリに標準で備わっている環境変数読み込み機能を使います。

Reactアプリのルートディレクトリに「.env」ファイルを作成して接頭辞「REACT_APP」の変数にFirebase側の作業で取得したAPIキーなどをセットします(ダブルクォーテーションは不要です)。「.env」は.gitignoreに設定しておきます。これだけで「process.env.<環境変数名>」として簡単に環境変数を参照することができます。

// .env
REACT_APP_FIREBASE_KEY=<apiKey>
REACT_APP_FIREBASE_DOMAIN=<authDomain>
REACT_APP_FIREBASE_DATABASE=<databaseURL>
REACT_APP_FIREBASE_PROJECT_ID=<projectId>
REACT_APP_FIREBASE_STORAGE_BUCKET=<storageBucket>
REACT_APP_FIREBASE_SENDER_ID=<messagingSenderId>

Firebase用機能を集約したコンポーネントを作成

Firebaseのための関数群はfirebase.tsxという1ファイルを作成してここに集約します。

下記赤字部分でFirebase接続用のキーを環境変数から参照してFirebase用インスタンスを取得しています。

青字部分で上から順にメール/パスワード認証のログイン、Google認証のログイン、メール/パスワード認証のサインアップ、ログアウト用の関数を定義しています。

緑字部分の主な処理はFirebaseに認証ユーザーを問い合せた後にユーザー情報をStateにセットしています。そしてContextを使って子コンポーネントにそのユーザー情報を渡せるようにしています。

// firebase.tsx
import React, { useEffect, useState } from 'react'
import firebase from 'firebase/app'
import 'firebase/auth'
import { FirebaseContext } from './contexts'

export const app = firebase.initializeApp({
    apiKey: process.env.REACT_APP_FIREBASE_KEY,
    authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
    databaseURL: process.env.REACT_APP_FIREBASE_DATABASE,
    projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
    storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
})

export const loginWithEmail = async (email: string, password: string) => {
    try {
        await app.auth().signInWithEmailAndPassword(email, password)
    } catch (error) {
        alert(error)
    }
}

export const loginWithGoogle = async () => {
    const provider = new firebase.auth.GoogleAuthProvider()
    try {
        await firebase.auth().signInWithPopup(provider)
    } catch (error) {
        alert(error)
    }
}

export const signupWithEmail = async (email: string, password: string) => {
    try {
        await app.auth().createUserWithEmailAndPassword(email, password)
    } catch (error) {
        alert(error)
    }
}

export const logout = () => {
    app.auth().signOut()
}

export const FirebaseProvider: React.FC = ({ children }) => {
    const [user, setUser] = useState(null)
    const [pending, setPending] = useState(true)

    useEffect(() => {
        app.auth().onAuthStateChanged((user) => {
            setUser(user)
            setPending(false)
        })
    }, [])

    if (pending) {
        return <div className='loading'>ローディング中...</div>
    }

    return (
        <FirebaseContext.Provider
            value={{
                user,
            }}
        >
            {children}
        </FirebaseContext.Provider'>
    )
}

 

子コンポーネント(Home)では下記緑字のとおりContextからユーザー情報を取得して利用しています。

// Home.tsx
import React, { useContext } from 'react'
import { logout } from '../firebase'
import { FirebaseContext } from '../contexts'

const Home = () => {
    const { user } = useContext(FirebaseContext)

    return (
        <>
            <header className='header-page'>
                <h1>Home(要ログイン)</h1>
            </header>
            <div className='wrap-home'>
                <p>{user?.email}でログインしています。</p>
                <button onClick={logout}>ログアウト</button>
           </div>
        </>
    )
}

export default Home

後続記事

関連記事

前回の記事(以下にリンク添付)ではFirebaseのAuthenticationを使って認証アプリを作成しましたが、本記事ではログインすると表示されるページにメモを追加/表示/更新/削除できる機能を実装します。データの保存にはFirebas[…]

home-screen

参考

React Router公式ドキュメント(認証サンプル)

ReactRouterWebsite

Learn once, Route Anywhere…

 

Firebase公式ドキュメント(Authentication)

sponsor