FirebaseAuthentication + Vue.jsでログイン認証を実装する

##前置き
Vue.jsとFirebaseAuthでどシンプルなログイン機能をつくります。今回はVue-CLIとVue-Routerを使用してSPAプロジェクトの雛形が用意されている前提で作成を進めていきます。
##STEP1
STEP1では各画面の作成をします。今回新規に作成するのは会員登録画面とログイン画面の2つです。デフォルトのホーム画面とアバウト画面は認証が必要なページとしてそのまま流用することにします。
###Bootstrap-vueの導入
では早速実装に、といきたいところですがその前にBootstrapを導入します。見た目は大事です。ターミナル(orコマンドプロンプト)で下記のコマンドを実行します。

```
cd xxxxx #Bootstrapを適用したいプロジェクトへ移動
npm install bootstrap-vue
```

yarnの場合は、

```
yarn add bootstrap-vue
```

でオッケーです。<br>インストールが完了したら、src/main.jsに下記の記述を追加してBootstrapをテンプレート内で使用できるようにします。

```javascript
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import 'bootstrap/dist/css/bootstrap.css' // 追加
import 'bootstrap-vue/dist/bootstrap-vue.css' // 追加
```

###各画面の作成
では改めて各画面を作成していきましょう。まずは会員登録画面とログイン画面です。ファイルはsrc/viewsの配下に設置します。

```vuejs:新規登録画面（src/views/Signup.vue）
<template>
  <div class="container">
    <h2>新規会員登録</h2>
    <div class="row d-flex flex-column align-items-center justify-content-center">
      <div class="col-md-4">
        <div class="form-group text-left">
          <label for="email">メールアドレス：</label>
          <input type="text" class="form-control" id="email" v-model="email">
        </div>
        <div class="form-group text-left">
          <label for="password">パスワード：</label>
          <input type="password" class="form-control" id="password" v-model="password">
        </div>
        <div class="form-group text-left">
          <label for="confirm-password">確認用パスワード：</label>
          <input type="password" class="form-control" id="confirm-password" v-model="confirmPassword">
        </div>
      </div>
      <div class="col-md-4 text-right">
        <button @click="userSignup" class="btn btn-primary my-3">登録</button>
      </div>
      <div class="col-md-4 text-center text-danger">
        {{ errorMessage }}
      </div>
    </div>
  </div>
</template>
```

```vuejs:ログイン画面（src/views/Signin.vue）
<template>
  <div class="container">
    <h2>ログイン</h2>
    <div class="row d-flex flex-column align-items-center justify-content-center">
      <div class="col-md-4">
        <div class="form-group text-left">
          <label for="email">メールアドレス：</label>
          <input type="text" class="form-control" id="email" v-model="email">
        </div>
        <div class="form-group text-left">
          <label for="password">パスワード：</label>
          <input type="password" class="form-control" id="password" v-model="password">
        </div>
      </div>
      <div class="col-md-4 text-right">
        <button @click="userSignin" class="btn btn-primary my-3">ログイン</button>
      </div>
    </div>
  </div>
</template>
```
次に認証成功時の遷移先としてホーム画面に手を加えます。デフォルトではsrc/components内のHelloWorld.vueを子コンポーネントとしてsrc/views内のHome.vueで読み込んで表示しています。今回はログインが確認できればいいので、下記のとおりtemplateの内容をまるっと書き換えます。

```vuejs:src/components/HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <button @click="signout" class="btn btn-danger">ログアウト</button>
  </div>
</template>
```
```vuejs:src/views/Home.vue
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Success!!!"/>
  </div>
</template>
```
ここまでで今回使用する画面のガワが完成しました。
###routerの設定
追加した画面を表示するにはrouterの設定が必要になります。まずは`src/router/index.js`に下記のコードを追記してログイン画面と新規登録画面のルーティングを設定します。

```javascript:src/router/index.js
  {
    path: '/signup',
    name: 'Signup',
    component: () => import(/* webpackChunkName: "signup" */ '../views/Signup.vue')
  },
  {
    path: '/signin',
    name: 'Signin',
    component: () => import(/* webpackChunkName: "signin" */ '../views/Signin.vue')
  }
```

次に認証後に表示したい画面にメタフィールドを定義します。今回はホームとデフォルトで用意されているAboutページを認証ページとして設定しました。

```javascript
meta: {requiresAuth: true}
```
最後にグローバルビフォーガードを設定して未承認時のリダイレクト先を指定します。
ここら辺の解説については[公式](https://router.vuejs.org/ja/guide/advanced/navigation-guards.html)に詳細があるのでそちらをご参照ください。

```javascript:src/router/index.js
import firebase from 'firebase'

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
  if (requiresAuth) {
    firebase.auth().onAuthStateChanged(function (user) {
      if (user) {
        next()
      } else {
        next({ name: 'Signin' })
      }
    })
  } else {
    next()
  }
})
```

##STEP2
STEP2ではアプリケーション内でFirebaseの機能を利用できるようにしていきます。
###Firebaseのインストール
ターミナル(orコマンドプロンプト)を開き、下記のコマンドを実行してFirebaseをインストールします。

```
npm install --save firebase
```
yarnの場合は

```
yarn add firebase
```

###FirebaseAuthを利用するための設定

FirebaseAuthを利用するにはFIrebase側でプロジェクトを用意する必要があります。まずは[こちら](https://console.firebase.google.com/)からFirebaseのプロジェクトを作成しましょう。<br>プロジェクトが作成できたら、プロジェクトの概要>Authenticationを開きます。
![スクリーンショット 2020-11-17 11.28.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/f89347bc-3dbc-361c-f6ca-51620ee3a2bd.png)<br>
今回はメールとパスワードに認証のみ実装するので、ログインプロバイダは「メール/パスワード」を選択し有効にします。
![スクリーンショット 2020-11-17 11.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/017cd89c-be5d-7f35-17bb-f0ec6f2e9c72.png)
次にアプリケーションとFirebaseを接続します。
プロジェクトの概要を開き、下記画像のアイコンをクリックをクリックするとアプリの登録画面が開きます。
![スクリーンショット 2020-11-18 15.44.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/510340b3-f31a-893f-d0f7-7169847fb982.png)<br>
「アプリの登録」画面で適当なニックネームをつけて「次へ」をクリックすると下記のような画面が表示されるので、赤枠内をすべてコピーします。![スクリーンショット 2020-11-18 16.08.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/3aa1424d-98e6-cf7d-8d79-6cbbb7f14854.png)
最後に先ほどコピーした内容をsrc/main.jsにペーストして、FirebaseをインポートすればVueアプリケーション内でFirebaseが提供するさまざまな機能を利用することができるようになります。

```javascript:src/main.js
import firebase from 'firebase'

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
var firebaseConfig = {
  apiKey: "xxxxxxxxxxxxxxxx",
  authDomain: "xxxxxxxxxxxxxxxx",
  databaseURL: "xxxxxxxxxxxxxxxx",
  projectId: "xxxxxxxxxxxxxxxx",
  storageBucket: "xxxxxxxxxxxxxxxx",
  messagingSenderId: "xxxxxxxxxxxxxxxx",
  appId: "xxxxxxxxxxxxxxxx",
  measurementId: "xxxxxxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
```
##STEP3
STEP3では、ユーザーの新規登録と認証機能の実装をおこないます。処理のほとんどはFirebase側がよろしくやってくれるので、基本的なVueの知識があれば躓くことはないと思います。
###新規登録&ログイン機能の実装
まずはユーザーを新規で登録する処理を実装していきます。

```vuejs:src/views/Signup.vue
<template>
  //省略
</template>
<script>
import firebase from 'firebase'
export default {
  data () {
    return {
      email: '',
      password: '',
      confirmPassword: '',
      errorMessage: '',
      isDisabeld: true
    }
  },
  methods: {
    checkPassword () {
      if (this.password !== this.confirmPassword) {
        this.errorMessage = 'パスワードが一致しません'
        this.isDisabeld = true
      } else {
        this.errorMessage = ''
        this.isDisabeld = false
      }
    },
    userSignup () {
      firebase
        .auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(() => {
          this.$router.push('/') //認証完了後のリダイレクト先を指定
        })
        .catch((e) => (this.errorMessage = e.message)) //エラーメッセージを格納
    }
  }
}
</script>
```
<br>
`methods`の`userSignup`メソッドでFirebaseにアクセスする処理を記述します。`createUserWithEmailAndPassword`メソッドの引数に入力されたメールアドレスとパスワードを設定することで値が送られ、登録と認証が行われます。`.then(() => {処理内容})`で成功時の処理を、`.catch((e) => (処理内容)`で失敗時の処理を記述しています。<br>`checkPassword`メソッドでは簡易的にパスワードの相違チェックをしていて、パスワードが確認用パスワードと一致しない場合は登録ボタンを無効化しメッセージを表示します。<br>最後に`http://localhost:8080/signup`にアクセスして実際にユーザー登録を行い、Firebase上に登録内容が反映されているかを見てみます。![スクリーンショット 2020-11-19 15.50.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/8df49158-4610-7f6a-d2a0-c140d52c795c.png)
Firebase>Authentication>usersにアクセスして以下のように表示されていれば登録は成功です！
![スクリーンショット 2020-11-19 15.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/e7f3ea15-4af2-74bb-2a11-628ab4c2a308.png)

次にログイン認証に実装を行います。新規登録と同様にFirebaseにメールアドレスとパスワードの情報を送るだけです。

```vuejs:src/views/Signin.vue
<template>
  //省略
</template>
<script>
import firebase from 'firebase'
export default {
  data () {
    return {
      email: '',
      password: '',
      errorMessage: ''
    }
  },
  methods: {
    userSignin () {
      firebase
        .auth()
        .signInWithEmailAndPassword(this.email, this.password)
        .then(() => {
          this.$router.push('/')
        })
        .catch((e) => (this.errorMessage = e.message))
    }
  }
}
</script>
```

新規登録の処理とほとんど変わりません。ログインボタンの`@click`イベントで`userSignin`メソッドを呼び出し、その中で入力内容を`signInWithEmailAndPassword`メソッドでFirebaseに送っています。<br>追記が完了したら`http://localhost:8080/signup`にアクセスして先ほど登録したメールアドレスとパスワードで正常にログインできるか確認します。正しく入力してログインボタンを押下した際エラーメッセージを表示せずホーム画面に遷移すれば成功です。
###ログアウト機能の実装
FirebaseAuthenticationの`signOut`メソッドをmethodsに定義することで簡単にログアウト機能を実装することが可能です。今回はログアウトボタンの`@click`イベントでsignoutメソッドを呼び出し処理を実行しています。

```vuejs:src/components/HelloWorld.vue
<template>
//省略
</template>
<script>
import firebase from 'firebase'
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  methods: {
    signout () {
      firebase.auth().signOut()
        .then(() => {
          this.$router.push('/signin')
        })
        .catch(error => {
          alert('ログアウトに失敗しました')
        })
    }
  }
}
</script>
```
最後に`http://localhost:8080/`にアクセスして認証が正常に動いているかを確認して完成です。
##さいごに
僕自身、Firebaseに触れたのは今回がはじめてだったのですが、サーバーサイドの知識なしに認証がこんなにも簡単に実装できるのには感動しました！この記事が、お手軽にフルスタック開発をしたい皆々様のご参考になれば幸いです。