前書き
Firebase Authenticationを使って認証を作成しましたが、リダイレクト方法の最適解がわからないためここに記します。リダイレクトに焦点を当てていますので細かい実装方は各自お願いします。
やりたいこと ~ リダイレクト処理 ~
- 認証がないのに認証必須ページにアクセスした場合、ログインページに遷移
- 認証があるのにログインページにアクセスした場合、認証必須ページに遷移
全体の流れ
- Firebase AuthをNuxt3で初期化
- Nuxt3でリダイレクトを実装
1. Firebase AuthをNuxt3で初期化
- Firebaseではアプリ立ち上げ時に一度だけ、Firebase認証(初期化)をする必要がある
- middlewareディレクトリに初期化処理を実装
※実際に使う場合は環境変数を直書きせずruntimeConfigなどを使用して下さい。
Nuxt3ではpluginsフォルダがアプリ立ち上げ時に一度だけ実行されるのでここに初期化処理を記述するのが主流ですが、後に説明する理由でmiddlewareに初期化処理を記述します。
middleware/firebaseinit.global.ts
// 拡張子にglobalを記述することで全ファイルに適応
import { initializeApp } from "firebase/app";
export default defineNuxtRouteMiddleware(() => {
const firebaseConfig = {
apiKey: "***************",
authDomain: "**************",
databaseURL: "**************",
projectId: "**************",
storageBucket: "**************",
databaseURL: "**************",
};
// 初期化
initializeApp(firebaseConfig)
})
2. リダイレクトをmiddlewareに実装
middlewareディレクトリはコンポーネントの読み込み前に実行されるディレクトリであり、一般的にはページに認証が必要かどうかなどに利用されます。
middleware/auth.ts
import { defineNuxtRouteMiddleware, navigateTo } from "nuxt/app";
import { getAuth, onAuthStateChanged } from "firebase/auth";
export default defineNuxtRouteMiddleware(async (to) => {
const auth = getAuth();
const user = await new Promise((resolve) => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
unsubscribe();
resolve(user);
});
});
// 認証がありログイン画面に遷移しようとした場合、ユーザー画面へ
if (user && to.path === "/") {
return navigateTo(`/member/${auth.currentUser?.uid}`);
}
// 認証がなくユーザー画面に遷移しようとした場合、ログイン画面へ
if (!user && to.path !== "/") {
return navigateTo("/");
}
});
以下のようにpagesディレクトリで記述するとmiddlewareが反映されます。
pages/member/index.vue
<script setup lang="ts">
definePageMeta(middleware: "auth");
</script>
<template>
<p>メンバーページ</p>
</template>
なぜpluginsに初期化を記述しないのか
middleware.globalで記述するとページごとに初期化されパフォーマンスは良くありません。
しかし、pluginsで初期化するとおそらくリロード時ライフサイクルの都合上初期化が間に合わず、認証があるのにも関わらずログイン画面に遷移orエラーになります。
ライフサイクル (多分)
- plugins (非同期)
- middleware.global
- middleware (plugins初期化途中)
よってNuxt3, Firebase Authを用いた認証のリダイレクトを実装する際には現在この記述を採用しています。自分の技量不足であまりいい記述とは言えませんがとりあえずこれで正常に動きます。何か詳しい方いたら教えていただけると幸いです。