概要
Next.js × TypeScript × Firebase Authenticationを用いたgoogle認証機能を実装してみました。
実装(Firebase側)
プロジェクトを作成する
Firebaseにアクセスし、新しいプロジェクトを作成します。
作成が完了したら、『ウェブ』というアイコンをクリックし、アプリ名の登録を行います。
アプリ名の登録が完了すると、下記のようなスクリプトが表示されるかと思います。
こちらはnextアプリ側で使うので、コピーしておきます。
var firebaseConfig = {
apiKey: xxxxx
authDomain: xxxxx,
databaseURL: xxxxx,
projectId: xxxxx,
storageBucket: xxxxx,
messagingSenderId: xxxxx,
appId: xxxxx,
measurementId: xxxxx
};
Google認証を有効にする
Firebaseのコンソール画面のSign-in methodタブにあるログインプロバイダの中でGoogle認証を有効化・無効化する部分があるので、まずそちらで有効化します。
これでFirebase側での設定は終了です。
実装(Next.js側)
インストール
firebase Authentication機能を利用したいので、
アプリケーションディレクトリにてfirebaseをインストールします。
$ yarn add firebase
必要ファイルを生成
.env
アプリケーションディレクトリにて.env
を生成します。
$ touch .env
$ vim .env
.env
にコピーしたスクリプトの値を記述していきます。
各個人、値が違うので適宜記述してください。
FIREBASE_API_KEY=xxxxx
FIREBASE_AUTH_DOMAIN=xxxxx
FIREBASE_DATABASE_URL=xxxxx
FIREBASE_PROJECT_ID=xxxxx
FIREBASE_STORAGE_BUCKET=xxxxx
FIREBASE_MESSEGING_SENDER_ID=xxxxx
FIREBASE_APP_ID=xxxxx
FIREBASE_MEASUREMENT_ID=xxxxx
設定し終えたら、.gitignoreに.envがpushされないように追加を忘れないでください。
next.config.js
.envの値をnextアプリでも利用できるようにnext.config.js
に記述していきます。
module.exports = {
env: {
FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
FIREBASE_DATABASE_URL: process.env.FIREBASE_DATABASE_URL,
FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
FIREBASE_MESSEGING_SENDER_ID: process.env.FIREBASE_MESSEGING_SENDER_ID,
FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID,
},
}
Firebase.ts
.envの値を利用し、Firebase.tsに設定を記述していきます。
import firebase from 'firebase'
const config = {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
databeseURL: process.env.FIREBASE_DATABASE_URL,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_MESSEGING_SENDER_ID,
appId: process.env.FIREBASE_APP_ID,
measurementId: process.env.FIREBASE_MEASUREMENT_ID,
}
// firebase.appsをチェックし、ロードされているかどうかを確認。
// なければinitializeAppを実行
if (!firebase.apps.length) {
firebase.initializeApp(config)
}
export default firebase
Auth.tsxでContextの作成
ユーザー情報の値をグローバルに持ち、バケツリレーを回避しつつ、Auth.tsx配下のコンポーネントたちに値が渡るようにContextの作成を行います。
import { User } from 'firebase';
import { FC, createContext, useEffect, useState } from 'react';
import firebase from '../utils/Firebase';
type AuthContextProps = {
currentUser: User | null | undefined
}
const AuthContext = createContext<AuthContextProps>({ currentUser: undefined });
const AuthProvider: FC = ({ children }) => {
const [currentUser, setCurrentUser] = useState<User | null | undefined>(
undefined
);
useEffect(() => {
// ログイン状態が変化するとfirebaseのauthメソッドを呼び出す
firebase.auth().onAuthStateChanged((user) => {
setCurrentUser(user);
})
}, []);
/* 下階層のコンポーネントをラップする */
return (
<AuthContext.Provider value={{ currentUser: currentUser }}>
{children}
</AuthContext.Provider>
)
}
export { AuthContext, AuthProvider }
_app.tsxにてComponentをAuthProviderでラップすることを忘れないでください。
import React, { useEffect } from 'react'
import { AppProps } from 'next/app'
import { AuthProvider } from '../context/Auth'
const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
return (
---略---
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
---略---
)
}
export default MyApp
サインイン画面
それでは実際にサインアップ画面の実装を行っていきます。
尚、今回はUI側の実装は簡易的なものになりますので、UI実装は適宜実装してください。
import { FC, useEffect, useContext } from 'react';
import Router from 'next/router';
import firebase from '../../utils/firebase';
import { AuthContext } from '../../context/Auth';
const SignIn: FC = () => {
const { currentUser } = useContext(AuthContext);
useEffect(() => {
currentUser && Router.push('/')
}, [currentUser]);
const login = () => {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithRedirect(provider);
}
return (
<div className="container">
<button onClick={login}>googleでログインする</button>
</div>
)
}
-
useContext
によって親よりすべての子たちがcurrentUser
という現在ログインしているユーザー情報の値を利用できるようにしています。
useState
と合わせて利用することでpropsによりバケツリレーを行うことなく、情報更新や値渡しが可能になり、複雑にならずに済むことがメリットです。 -
useEffect
によってもし現在クライアントがログインしていた場合、ホーム画面へリダイレクトするようにしています。[currentUser]
の部分はcurrentUser
の値が変更された場合、useEffect
が発火するようにしています。
動作確認
実装が完了したら、ホーム画面でcurrentUserのメールアドレスなどを表示させてみましょう。