Vue.jsとfirebaseを使ってTwitter認証してみた【ユーザー名・プロフ写真の取得と表示・ログイン状態維持の方法も併せて】

#はじめに
個人開発をしようと思い、フロントに***Vue.js***、バックエンドに***Go***を使うことに決めました。

よくある組み合わせですね。

制作物のテーマはTwitterを活用するものになる？予定なので、ログイン機能もTwitter認証を用いてログインする形式を採用することにしました。
認証にあたり***firebase***を用いると簡単に認証ができるということなので、今回活用してみることにしました。

結果として、***「認証」だけなら簡単でした。***(恐らく記事を探せば認証に関してはすぐ見つかると思います。)

ユーザー名とプロフ写真のURLの取得、ログイン状態の維持に関してはあまり記事がなく、3日間くらい悩みました。
同じように悩む人がいると思うので(~~私が雑魚なだけ？~~)、備忘録兼同じことをやりたい人の為に、ここに載せておきます。

#準備するもの
firebaseからTwitter認証できるように、TwitterAPIを入力する項目があります。
そのため、あらかじめTwitterAPIを取得していないといけません。
API取得に関してはここでは紹介いたしませんので、別途個人で取得をお願いいたします。

また``Vue``xと``vue-router``も使うので、入れていない人は追加をお願いします。

#実際の画面#
①signinボタンをクリックする
![](https://uploader.xzy.pw/upload/20190926011409_6e31374766.png)
②Twitter連携のポップアップが表示される

![](https://uploader.xzy.pw/upload/20190926011409_6e65696f51.png)
③連携アプリを認証し、ホーム画面へ
Twitterのユーザー名・プロフィール写真も表示される

![](https://uploader.xzy.pw/upload/20190926011409_6931795333.png)


#Twitter認証方法
##`ログイン`##
下記の通り、Signinボタンを押すとクリックイベントに応じて、signinメソッドが実行されます。
signinメソッドの``function()``以降がログインに関わる部分です。

firebaseのDocsにあるTwitter認証のリファレンスと[こちらの記事](https://qiita.com/mugi_chan_tea/items/48ed824cf8b3ff8da226)を参考に、ここの処理を作成しました。

今回はユーザー名・プロフ写真が欲しいので、ログインユーザーのユーザー名とプロフ写真のURLを取得し、格納する``currentUser``プロパティを用意します。

``currentUser``の情報は全画面共通で使いたい(例えばQiitaは、どの画面に飛んでも自分のTwitterのプロフ写真が載ってますよね？)ので、``store.js``にcommitして送ります。

後半のエラー処理に関してはよく分からなかったので、とりあえず書いただけです。あまり参考にしないで下さい…。

```components/signin.vue
<template>
  <div class="signin">
    <h2>Sign in</h2>
    <button @click="signin">Signin</button>
  </div>
</template>

<script>
import firebase from "firebase";

export default {
  name: "Signin",
  methods: {
    signin: function() {
      var provider = new firebase.auth.TwitterAuthProvider();
      firebase
        .auth()
        .signInWithPopup(provider)
        .then(
          result => {
            var token = result.credential.token;
            var secret = result.credential.secret;
            var user = result.user;
            if (user) {
              const currentUser = { // ←こいつ必要
                displayName: user.displayName,
                photoURL: user.photoURL
              };
              this.$store.commit("setUser", currentUser); // currentUserをstore.jsに渡す
              this.$router.push("/");
            } else {
              alert("有効なアカウントではありません");
            }
          },
          err => {
            alert(err.message);
          }
        );
    }
  }
};
</script>
```
```store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  // strictモードは本番環境ではfalseにすること
  strict: true,
  state: {
    user: {
      displayName: "",
      photoURL: ""
    }

  },
  getters: {
    getURL(state) { // ←こいつは後半に使う処理なので覚えておいてください
    return state.user.photoURL
    }
  },
  mutations: {
    setUser(state, currentUser) { // commitされるとmutationsのsetUserが実行される
      state.user.displayName = currentUser.displayName // ここでユーザー名をstateにセットできる
      state.user.photoURL = currentUser.photoURL // 同様に写真URLをセットする
    }
  },
  actions: {

  }
})
```
##`ログイン状態の維持`##
ログイン状態の維持には``firebase.auth().onAuthStateChanged()``を使います。
ここら辺に関してはまだ詳しくないので、うまく説明することができないのです。すみません。

ただ見てもらえれば分かる通り、ログイン状態であるかどうかの判別をここでしています。

ログイン状態であればstore.jsに、上記同様currentUserを引数にしてcommitします。
維持というよりは更新と言った方が正確かもしれません。

画面が変わるごとに最新の状態に更新しているの、最新の状態に保つ＝維持ともいえるということなのでしょうね。

```main.js
// 認証状態を確認
// Vueのインスタンス化
const app = () => {
  firebase.auth().onAuthStateChanged(currentUser => {
    if (currentUser) {
      store.commit("setUser", currentUser)
    } else {
      store.commit("setUser", null)
    }
  }),
    /* eslint-disable */
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
}
// 関数実行
app()
```

##`ユーザー名・プロフ写真の取得`##
他にも色々なものが下記のコードに入っているのですが、見づらさが増すので必要な部分だけ記載しております。

このコンポーネントで行っていることはいたってシンプルです。

``store.js``の``state``の値を持ってきているだけです。

今回は勉強もかねて``mapState``と``mapGetters``を使用しています。

注意する点というか私がハマった点は、
***src属性にどうやってstore.jsのuserプロパティのphotoURLを入れるのか***
というところです。(Vue.js初心者なのでまったくわかりませんでした...)


```components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>Hello</h1>
    <p>{{ user.displayName }}</p> <!--userのdisplayName(あなたのTwitterのユーザー名)を表示します-->
    <img :src="url" /> <!--mapGettersのurl(←名前は何でもいい)をv-bindしたsrc属性に記述してください-->
    <h2>Essential Links</h2>
  </div>
</template>

<script>
import firebase from "firebase";
import { mapState, mapGetters } from "vuex";
export default {
  name: "HelloWorld",
  data() {
    return {
  },
  computed: {
    ...mapState({
      user: state => state.user // stateのuserプロパティを取得する処理にuserという別名を与える
    }),
    ...mapGetters({ url: "getURL" }) // mapGettersのgetURLに別名を与える
  }
};
</script>
```

まずVueのルールで\``<img src={{ user.photoURL }} />``のような記述をすることはできません。

\``<img :src={{ user.photoURL }} />``のような書き方をしたいところですが、
``data``に値がないのでこれもエラーとなります。

結果としては``getters``経由で取得することができたので、今回はこのように処理することが正解なのかもしれないですね。

#終わりに#
一連の処理については以上となります。

私自身、まだエンジニア歴半年になるかならないかぐらいの素人なので、今回の投稿内容も正確さに欠ける点が多いと思います。
参考の参考程度にしていただくだけでも幸いです。