[Advent Calendar 2021][Day12]Firebase Authenticationを利用してユーザ登録・削除機能を作る

はじめに

Advent Calendar 2021のDay12。 今回は、Firebase Authenticationを利用してユーザ登録・削除機能を作ります。

firebaseプロジェクトを作成する

FirebaseプロジェクトをFirebaseのコンソールから作成する。 プロジェクト名には、すでに作成しているGCPプロジェクトを指定します。 表示されたfirebaseConfigenv.development.tsにコピーします。先頭にexportをつけておき、後ほどimportします。

  • nuxt3-app/env.development.ts
export const firebaseConfig = {
  apiKey: "xxx",
  // 省略
};

firebaseをインストールする

yarn add firebase

firebaseのPluginを作成する

env.development.tsを読み込めるようnuxt.config.tsを修正します。

  • nuxt3-app/nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3'
+import { firebaseConfig } from './env.development'

// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
export default defineNuxtConfig({
    publicRuntimeConfig: {
        graphqlURL: process.env.GRAPHQL_URL,
+        firebaseConfig
    },
})

今回は、ユーザ登録削除機能をつくります。また、ログイン・ログアウト機能もつくります。ユーザ登録は、SignInにより自動的にFirebaseAuthenticationによりユーザ登録されます。StateにTokenUserを保存します。

  • nuxt3-app/plugins/firebase.ts
import { initializeApp } from "firebase/app";
import { getAuth, signInWithPopup, signOut, deleteUser, GoogleAuthProvider, UserCredential } from "firebase/auth";
import { defineNuxtPlugin } from '#app'
import { ref } from "vue";

export default defineNuxtPlugin(nuxt => {
    const { vueApp } = nuxt

    // Initialize Firebase
    initializeApp(nuxt.$config.firebaseConfig);
    const auth = getAuth()
    const provider = new GoogleAuthProvider();

    // state
    const tokenState = useState('token', () => null)
    const userState = useState('user', () => null)
    if (process.client) {
        auth.onAuthStateChanged(async (user) => {
            if (user) {
                console.log('loggedIn')
                userState.value = user
                user.getIdToken().then(token => {
                    tokenState.value = token
                })
            } else {
                console.log('loggedOut')
                userState.value = null
                tokenState.value = null
            }
        })
    }

    // provide firebase
    const firebase: FirebasePlugin = {
        signIn: () => {
            return signInWithPopup(auth, provider)
        },
        signOut: () => {
            return signOut(auth)
        },
        deleteUser: () => {
            return deleteUser(auth.currentUser)
        }
    }
    nuxt.provide('firebase', firebase)
    vueApp.provide('$firebase', ref(firebase))

})

interface FirebasePlugin {
    signIn: () => Promise<UserCredential>
    signOut: () => Promise<void>
    deleteUser: () => Promise<void>
}

declare module '#app' {
    interface NuxtApp {
        $firebase: FirebasePlugin
    }
}

urqlにTokenを設定する

useStateを使って、Tokenを設定します。

    const client = createClient({
        url: nuxt.$config.graphqlURL,
+        fetchOptions: () => {
+            if (process.client) {
+                const token = useState('token').value
+                return {
+                    headers: { authorization: token ? `Bearer ${token}` : '' },
+                };
+            }
+            return {}
+        },
+        exchanges: [
            dedupExchange,
            ssr,

参考

https://formidable.com/open-source/urql/docs/basics/vue/#setting-up-the-client

pageにログイン・ログアウト機能を追加する

                <em>no results</em>
            </div>
        </div>
+        <button v-if="!user" @click="nuxtApp.$firebase.signIn()">login</button>
+        <template v-else>
+            <button @click="nuxtApp.$firebase.signOut()">logout</button>
+            <button v-if="user" @click="nuxtApp.$firebase.deleteUser()">deleteUser</button>
+        </template>
    </section>
</template>

<script setup lang="ts">
import { MyQueryDocument } from "~/gql/queries/calendar";
import { useClientHandle } from "@urql/vue";
+import { useNuxtApp } from '#app'
const urql = useClientHandle();
const { data, fetching } = await urql.useQuery({ query: MyQueryDocument })
+const nuxtApp = useNuxtApp()
+const user = useState<boolean>('user')
</script>

まとめ

今回は、Firebase Authenticationを利用してユーザ登録・削除機能を作りました。 次回は、HasuraGraphQLの認可機能を使って権限を制御します。