【Firebase Authentication】Nuxt.jsで作成したアプリケーションにログイン機能をつける。

## Nuxt.jsでのログイン実装
現在ユーザー機能が必要なアプリケーションを作成しているため,ログイン機能を実装する必要があります。
Firebase Authenticationの機能を使って登録したユーザーがログインできるかを確認します。

## 前提
・Firebaseが使える状態にある
・axiosがインストール済みである

## ページ構成
よくあるヘッダーの右側にログイン、サインインがあるパターンを想定します。
こんな感じです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/b8a7f31c-d571-90fe-dadd-a8a956145c2c.png" width="70%">

まずはリンク先のページをpages配下に用意してあげましょう。

```shell

touch pages/login.vue
```

続いてヘッダーにリンクを用意してあげましょう。
Nuxtはルーティングが簡単にできるからとても便利ですね。

```vue:header.vue
<ul class="list-inline">
  <li class="list-inline-item"><n-link to="/login">Log in</n-link></li>
</ul>
```

## loginフォームを用意する
シンプルなフォームがほしかったためこちらからお借りしました。

https://codepen.io/colorlib/pen/rxddKy

## Firebase Authenticationでユーザーを用意
1.Authenticationをクリック
2.ユーザーを追加をクリック
3.メールアドレスとパスワードを入力（存在しないもので構いません）
4.ユーザーを追加をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/ef8a10d8-b6d2-4984-4938-74571e49c4f3.png" width="70%">
####Sign-in methodの設定
1.Sign-in methodをクリック
2.メール/パスワードを有効化
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/7898d3ee-66c0-1bf7-3c69-11092e65604c.png" width="70%">

#### plugins/firebase.jsを用意
firebaseの情報を設定します。
1.プロジェクトの概要　> 歯車をクリック > プロジェクトを設定をクリック
2.全般をスクロールする

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/0c6a0f90-2659-3c6e-0ffa-642c2d718c36.png" width="70%">

こちらの画面をスクロールすると表示される情報ですね。

```javascript:plugins/firebase.js

const config = {
  apiKey: "{{ APIKEY }}",
  authDomain: "{{ AUTHDOMAIN }}",
  databaseURL: "{{ DATABASEURL }}",
  projectId: "{{ PROJECTID }}",
  storageBucket: "{{ STORAGEBUCKET }}",
  messagingSenderId: "{{ MESSAGINGSENDERID }}",
  appId: "{{ APPID }}",
  measurementId: "{{ MESUREMENTID }}"
};

// Initialize Firebase
if (!firebase.apps.length) {
  firebase.initializeApp(config);
}

export default firebase;
```

## storeを用意する
データを保存しておくという仕組みしか理解しておりませんので、提供いただいたコードをそのまま掲載します。

```javascript:store/index.js
import firebase from '~/plugins/firebase'

// data保管庫
export const state = () => ({
  user: {
    uid: '',
    email: '',
    login: false,
  },
})

// stateの情報を取得
export const getters = {
  user: state => {
    return state.user;
  }
}

// storeの上書き以外の処理や非同期通信
export const actions = {
  login({ dispatch }, payload) {
    // メールとパスワードでログイン
    console.log('login action');
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => {
        console.log('ログイン成功！');
        this.$router.replace({ path: '/' });
        dispatch('checkLogin')
      })
      .catch((error) => {
        alert(error);
      })
  },
  loginGoogle({ dispatch }) {
    // Googleアカウントでログイン
    console.log('loginGoogle action');
    const provider = new firebase.auth.GoogleAuthProvider();
    firebase.auth().signInWithPopup(provider)
      .then(result => {
        const user = result.user;
        console.log('googleログイン成功！');

        dispatch('checkLogin');
      })
      .catch((error) => {
        alert(error);
      });
  },
  checkLogin({ commit }) {
    // ログインしているかどうかのチェックログインしていたらデータ追加
    firebase.auth().onAuthStateChanged((user) => {
      console.log(user);
      if (user) {
        console.log(user);
        commit('login', { uid: user.uid, email: user.email });
      }
    })
  },
  logout({ commit }) {
    // ログアウト
    firebase.auth().signOut()
      .then(() => {
        console.log("ログアウトしました");
        commit('logout');
      })
      .catch((error) => {
        console.log(`ログアウト時にエラーが発生しました (${error})`);
      });
  }
}

// stateの上書き(代入)
export const mutations = {
  login(state, payload) {
    state.user.uid = payload.uid;
    state.user.email = payload.email;
    state.user.login = true;
  },
  logout(state) {
    state.user.uid = '';
    state.user.email = '';
    state.user.login = false;
  }
}

```
## 
ここまでで下準備が終わりました

login.vueから実処理を行うLoginMenuのコンポーネントを呼び出します

```javascript:pages/login.vue
<template>
    <div>
      <h1>Log In</h1>
      <LoginMenu />
      <h3 v-if="user.login">
       ログインしました
      </h3>
      <h3 class="title" v-else>
       ログインしてください
      </h3>
    </div>
</template>

<script>
  import LoginMenu from "@/components/loginMenu.vue";
  export default {
    components: {
      LoginMenu: LoginMenu,
    },
    computed: {
        user() {
          return this.$store.getters["user"];
        },
    }
  };
</script>

```
```javascript:components/loginMenu.vue
<template>
<div class="login-page">
  <div class="form">
    <div class="register-form" v-if="this.$route.path === '/signup'">
      <input type="text" placeholder="name"/>
      <input type="password" placeholder="password"/>
      <input type="text" placeholder="email address"/>
      <button>create</button>
      <p class="message">Already registered? <n-link to="/login">Sign In</n-link></p>
    </div>
    <div class="login-form" v-else>
      <input type="text" v-model="email" placeholder="username"/>
      <input type="password" v-model="password" placeholder="password"/>
      <button v-on:click="login">login</button>
      <p class="message">Not registered? <n-link to="/signup">Create an account</n-link></p>
    </div>
  </div>
</div>
</template>

<script>
export default {
 computed: {
   // dataのように扱える
   // dataを作る前処理が必要な際に利用
   user () {
     return this.$store.getters['user'];
   },
 },
 data () {
   return {
     email: '',
     password: '',
   }
 },
 mounted() {
   // ログインしているかどうかのチェックログインしていたらデータ追加
   this.$store.dispatch('checkLogin');
 },
 methods : {
   async login () {
      // メールとパスワードでログイン
      console.log('login action', this.email, this.password);
      this.$store.dispatch('login', {email:this.email, password:this.password});
   },
   loginGoogle() {
      // Googleアカウントでログイン
      this.$store.dispatch('loginGoogle');
   },
   logout : function() {
      // ログアウト
      this.$store.dispatch('logout');
   }
 }
}
</script>

```


## ログイン可能か確認する
ひとまずログインを行うと右のメニューがlogoutになるか確認します。

```javascript:header.vue
<template>
    <nav class="navbar navbar-light bg-light">
        <h1><n-link to="/">title</n-link></h1>
        <ul class="list-inline" v-if="user.login">
            <li class="list-inline-item"><n-link to="/logout" >Log Out</n-link></li>
        </ul>
        <ul class="list-inline" v-else>
            <li class="list-inline-item"><n-link to="/login">Log in</n-link></li>
            <li class="list-inline-item"><n-link to="/signup">Sign up</n-link></li>
       </ul>
    </nav>
</template>
```

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">nuxt.jsとFirebase Authenticationでログインフォームからログイン<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/rDzU3q17P6">pic.twitter.com/rDzU3q17P6</a></p>&mdash; ウーリズム (@Uh_rhythm) <a href="https://twitter.com/Uh_rhythm/status/1316367308898463745?ref_src=twsrc%5Etfw">October 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## ひとまず作りながら覚えていく
Nuxt.jsは以前から何度か触れていましたが複数ページにまたがる物を作るのは今回が初めてだったため
作りながら覚えていくことになります。
ひとまずstoreやstateについて早急に学んでいく必要がありますね。