VueとFirebaseを使ってログイン機能を作るには?

記事
IT・テクノロジー

VueとFirebaseを使ってログイン機能を作るには?


Vue の基本を一通り学習したところで少し実践的な実装例を紹介します。この記事では、Firebase のユーザー認証機能を利用して、ログイン機能を Vue で作成する例を紹介します。

Vue のプロジェクトを作成

今回は、Vue Router や Pinia などを使わずにシンプルに、ホームページを表示するという簡単な例にしてみました。

簡単に実装内容を説明すると:

* ログインしていない場合は、ログインフォームを表示
* ログインしている場合には、「Home.vue」を表示
という仕様にします。

ログインフォームは再利用できるように「部品化」します。

「src/App.vue」で表示の切り替えをするようにします。 「src/components/LoginForm.vue」でログインに必要な情報を入力するフォームを作成します。「src/view/Home.vue」がホームページになります。

まずは、サンプルプロジェクトを作成します。

$ npm init vue
Vue.js - The Progressive JavaScript Framework

✔ Project name: … vue-firebase-sample
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes

Scaffolding project in /home/guest/vue-firebase-sample...

Done. Now run:

  cd vue-firebase-sample
  npm install
  npm run dev

$ cd vue-firebase-sample
$ npm install
Firebase の基本モジュールをインストールします。

$ npm install firebase

不要なファイルを削除します。

$ rm src/assets/*
$ rm src/views/*
$ rm -rf src/components/*
ホームページを作成します。

(src/views/Home.vue)
<template>
  <div>
    <h1>Welcome!</h1>
    <p>{{ email }}</p>
  </div>
</template>
<script>
export default {
  props: ["email"],
};
</script>

Firebase を使う準備

Firebase を利用するためには、Firebase を初期化する必要があります。

まずは、Firebase プロジェクトを作成してください。 Firebase プロジェクトはFirebase コンソールで作成します。その上で、Firebase のプロジェクトの情報を、使って Firebase を初期化します。

//(src/assets/firebase.js)
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: "ABCDEFGHIr0abcdefghijklmnopqrstuvwxyz01",
  authDomain: "test-xxxx.firebaseapp.com",
  databaseURL: "h t t p s://test-xxxx.firebaseio.com",
  projectId: "test-xxxx",
  storageBucket: "test-xxxx.appspot.com",
  messagingSenderId: "0123456789012",
  appId: "1:0123456789012:web:0123456789abcdefghijkl",
};

export const firebase = initializeApp(firebaseConfig);
export const auth = getAuth(firebase);

これで Firebase が初期化されました。

App.vue を書き換える

Firebase が初期化されたところで、「App.vue」を書き換えて、ログイン画面とホームページを切り替えられるようにします。

「App.vue」で、ログインの状態と、E-Mail アドレス、ユーザー Id(uid)を保持するようにします。

<script>
import {
  browserSessionPersistence,
  onAuthStateChanged,
  setPersistence,
  signInWithEmailAndPassword,
  signOut,
} from "firebase/auth";
import { auth } from "./assets/firebase";
import Login from "./components/LoginForm.vue";
import Home from "./views/Home.vue";
export default {
  components: { Home, Login },
  data() {
    return {
      login: {
        status: false,
        email: "",
        uid: "",
      },
    };
  },
  methods: {
    loginEvent(email, password) {
      signInWithEmailAndPassword(auth, email, password)
        .then((userCredential) => {
          this.login.status = true;
          this.login.email = userCredential.user.email;
          this.login.uid = userCredential.user.uid;
          console.log(this.login);
        })
        .catch((err) => {
          this.login.status = false;
          this.login.email = "";
          this.login.uid = "";
        });
    },
    logoutEvent() {
      signOut(auth).then(() => {
        this.login.status = false;
        this.login.email = "";
        this.login.uid = "";
      });
    },
  },
  created() {
    setPersistence(auth, browserSessionPersistence).then(() => {
      auth.updateCurrentUser
        .then((user) => {
          if (user) {
            this.login.status = true;
            this.login.email = user.email;
            this.login.uid = user.email;
          } else {
            this.login.status = false;
            this.login.email = "";
            this.login.uid = "";
          }
        })
        .catch((error) => {
          this.login.status = false;
          this.login.email = "";
          this.login.uid = "";
        });
    });
    onAuthStateChanged(auth, (user) => {
      if (user) {
        this.login.status = true;
        this.login.email = user.email;
        this.login.uid = user.uid;
      } else {
        this.login.status = false;
        this.login.email = "";
        this.login.uid = "";
      }
    });
  },
};
</script>

<template>
  <div>
    <header>
      <nav>
        <a v-if="login.status" class="sign-out-link" @click="logoutEvent()"
          >Sign out</a
        >
      </nav>
    </header>
    <div v-if="login.status">
      <Home :email="login.email" />
    </div>
    <div v-if="!login.status">
      <Login @formData="(data) => loginEvent(data.email, data.password)" />
    </div>
  </div>
</template>
ログインの処理は、Firebase の API を呼び出す事で処理できます。 プログラムで新しくユーザーを作成する事もできますが、今回は Firebase コンソールで作成しておく事にします。

ログイン/ログアウトの処理は、

*「signInWithEmailAndPassword()」
*「signOut()」
を呼び出します。これで、Firebase の基本的なログイン・ログアウトの処理ができます。 ログインが成功した場合は、ログイン状態と、E-Mail アドレス、uid を更新します。

ログインとログアウトの処理です。

methods: {
    loginEvent(email, password) {
      signInWithEmailAndPassword(auth, email, password)
        .then((userCredential) => {
          this.login.status = true;
          this.login.email = userCredential.user.email;
          this.login.uid = userCredential.user.uid;
        })
        .catch((err) => {
          this.login.status = false;
          this.login.email = "";
          this.login.uid = "";
        });
    },
    logoutEvent() {
      signOut(auth).then(() => {
        this.login.status = false;
        this.login.email = "";
        this.login.uid = "";
      });
    },
  },

初期化の処理は、「created() {}」の中で行います。 一つは、ログイン状態の変化を「onAuthStateChanged()」で監視します。

onAuthStateChanged(auth, (user) => {
  if (user) {
    this.login.status = true;
    this.login.email = user.email;
    this.login.uid = user.uid;
  } else {
    this.login.status = false;
    this.login.email = "";
    this.login.uid = "";
  }
});
これで、ログイン状態が変化した場合は、ログインの状態と E-Mail アドレスと uid を更新します。「user」が有効な場合は、ログインの処理を、無効な場合はログアウトの処理を行います。

もう一つは、ログイン状態を保持する条件を設定します。

setPersistence(auth, browserSessionPersistence).then(() => {
  auth.updateCurrentUser
    .then((user) => {
      if (user) {
        this.login.status = true;
        this.login.email = user.email;
        this.login.uid = user.email;
      } else {
        this.login.status = false;
        this.login.email = "";
        this.login.uid = "";
      }
    })
    .catch((error) => {
      this.login.status = false;
      this.login.email = "";
      this.login.uid = "";
    });
});

この設定の場合、ブラウザの同じタブを利用している場合は、以前のログインの状態を保持する設定です。新しいタブを開いた場合には、ログイン処理をやり直す必要があります。

あとは、状態によって表示を切り替えるのは、「v-if」を使って HTML で記述します。

<template>
  <div>
    <header>
      <nav>
        <a v-if="login.status" class="sign-out-link" @click="logoutEvent()"
          >Sign out</a
        >
      </nav>
    </header>
    <div v-if="login.status">
      <Home :email="login.email" />
    </div>
    <div v-if="!login.status">
      <Login @formData="(data) => loginEvent(data.email, data.password)" />
    </div>
  </div>
</template>
「login.status」で表示を切り替えます。ログイン状態の場合は、「Sign out」の処理を行うメニューを一番上に出すようにしています。

利用者限定のサービスが簡単に実現できる

これで、ログインしていない場合には、常にログインフォームが表示されるようになります。ログインしている場合は、ホームページが表示されます。 今回は、「Welcome!」とログインしているユーザの E-Mail アドレスを表示しているだけですが、ここで提供しているアプリのプログラムを実装すると、ユーザー限定のサービスにする事ができます。

ユーザーの管理とログイン状態の管理は、Firebase が行なってくれるので、特別にバックエンドのサービスを作らなくても、こうした機能を簡単に実現できます。

まとめ

Vue と Firebase を組み合わせると、Firebase のログイン機能を利用して、利用者限定のサービスを簡単に実現できます。 Firebase のようなサービスを利用しない場合、バックエンドにデータベースをサーバー側に作って、Web サーバーにバックエンドのサービスを作成して、ユーザーの管理やログインの処理を作る必要があります。それだけで、必要な開発量は増えてしまいますが、そうした手間をかける事なく、初心者でも簡単に本格的なサービスが実装で  きます。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す