前提の話
Firebaseの初期化の設定などはここでは省略します。今回はGoogleアカウントでの認証を例にメモ的な感じでまとめています。
実装としてはGoogleアカウントで認証し、登録情報をFirestoreに登録するといった流れです。
NuxtとFirebaseのバージョンは以下の通りです。
- Nuxt: 3.0.0
- Firebase: 9.15.0
Googleアカウントで認証する
Googleアカウントで登録する流れを実装していきます。
まずは登録するための画面をcomponentsに作成します。このコンポーネントはpagesで呼び出すイメージです。
「Googleで登録」のボタンを押下するとgoogleSignUpメソッドが呼び出されます。ここでのuseAuth()とgoogleSignUpメソッドは後ほど実装していきます。
・components/SignUpForm.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <template> <div class="signup-form"> <p class="title">SNSアカウントで登録</p> <ul class="signup-buttons"> <li><button class="google-button" @click="googleSignUp"><i><GoogleLogo></GoogleLogo></i><span>Googleで登録</span></button></li> </ul> </div> </template> <script setup lang="ts"> import GoogleLogo from '@/assets/svg/icons/google-logo.svg' const googleSignUp = () => { const { googleSignUp } = useAuth() googleSignUp() } </script> |
「Googleで登録」のボタンを押下したgoogleSignUpメソッドがここで呼ばれます。GoogleAuthProviderのインスタンスを作成し、signInWithPopupを呼び出すことで、Google認証にポップアップが表示されます。
Google認証が完了したら、そのデータを元にgetUserメソッドでFirestoreのデータを取得しにいきます。
既にFirestoreにデータがある場合は、認証完了済みなのでログイン画面に遷移させます。データがない場合は新規登録なので、新しくFirestoreにuserデータを登録し、mypage画面に遷移させます。
最後にupdateUserメソッドを呼び出し、useState() を使ってuserの状態管理をしています。alertのところはいい感じのポップアップかトーストを実装したいところです。
・composables/useAuth.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | import { Auth, User, UserCredential, onAuthStateChanged, signInWithPopup, GoogleAuthProvider, } from "firebase/auth"; import { computed, ref } from "vue"; import { collection, where, query, getDocs, addDoc } from '@firebase/firestore'; export function useAuth() { const { $auth, $firestore } = useNuxtApp() const user = ref<User | null>($auth.currentUser); const isAuthed = computed(() => !!user.value); const db = $firestore; $auth.onIdTokenChanged((authUser) => (user.value = authUser)); // ユーザー情報取得 const getUser = async (uid: string): Promise<any> => { const q = query( collection(db, 'users'), where("uid", "==", uid) ); const querySnapshot = await getDocs(q); return querySnapshot.docs[0] }; // ユーザー作成 const createUser = async (user: UserCredential) => { await addDoc(collection(db, 'users'), { uid: user.user.uid, name: user.user.displayName, email: user.user.email, photo: user.user.photoURL }) }; // Google新規登録 async function googleSignUp() { try { const provider = new GoogleAuthProvider(); const googleUser = await signInWithPopup($auth, provider); const user = await getUser(googleUser.user.uid) const { updateUser } = await useUser() if (user) { alert("既にユーザー登録されています。") updateUser(user.data()) navigateTo("/login", { replace: true }) } else { alert("新規登録完了しました") await createUser(googleUser) const user = await getUser(googleUser.user.uid) updateUser(user.data()) navigateTo("/mypage", { replace: true }) } } catch (error) { throw error; } } async function currentUser() { return $auth.currentUser } return { isAuthed, user, checkAuthState, googleSignUp, currentUser }; } |
updateUserメソッドを使ってuserのstateの状態を管理しています。
認証後はuserのstateにUser情報を入れ、ログアウトなどの認証情報が破棄された場合はnullを入れます。
・composables/useUser.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { User } from "firebase/auth" import { Ref } from "vue" export const useUser = () => { const user: Ref<User | null> = useState<User | null>('user') const updateUser = (user: Ref<User | null>) => (value: User | null) => { user.value = value } return { user: readonly(user), updateUser: updateUser(user) } } |
認証状態のチェック
認証後のマイページに認証されていない場合はアクセスできないようにしたい場合、認証状態をチェックするなどの処理が必要になります。
その場合はmiddlewareで認証状態をチェックし、認証されていない場合はログインページに遷移させるなどの処理を実装します。
definePageMetaで指定してあげることで、このmiddlewareの処理が実行されます。
また、ログイン済みの場合にログインページを表示する場合は、マイページに遷移させるなどの処理も必要になるかと思います。
・middleware/auth.global.ts
1 2 3 4 5 6 7 8 9 10 | export default defineNuxtRouteMiddleware(async () => { if (!process.server) { const { isAuthed, checkAuthState } = useAuth(); await checkAuthState(); if (!isAuthed.value) { window.location.href = "/login"; } } }); |
全てのルートで実行したい処理がある場合は、Nuxt3のグローバルミドルウェアを使うことで実現できます。
.globalが付いたファイルは呼び出し処理を書かずに全てのルートで実行されます。
・middleware/auth-check.global.ts
1 2 3 4 5 6 | export default defineNuxtRouteMiddleware(async () => { if (!process.server) { const { checkAuthState } = useAuth(); await checkAuthState(); } }) |