Techvenience

Technology × Convenience - Vue / React / Next / Nuxt / ChatGPTなどのIT技術がもたらす便利さをお伝えします。最近はChatGPTなどのAI技術を使ってブログを書いています。

【Vue.js】Vue.js(Nuxt.js)でユーザー登録・ログイン・ログアウトなどの認証機能を簡単に実装する with Firebase【Firebase Auth】

【Vue.js】Vue.js(Nuxt.js)でユーザー登録・ログイン・ログアウトなどの認証機能を簡単に実装する with Firebase【Firebase Auth】

f:id:duo-taro100:20160218004611p:plain

今回はVue.jsで作成するアプリケーションに認証機能を実装します。
Firebase Authenticationを使いますので、手間なく速攻で実装が可能です。
今回はNuxt.jsを使っています。Nuxt.jsの環境が整っていない方は以下のページを参照して下さい。

www.sky-limit-future.com

目次

今回作りたい画面はこれです。

vueproducts-skylimitfuture.firebaseapp.com


当画面は随時更新中ですので、若干解説内容と異なる箇所がありますがご了承ください。

Firebase側の設定

まずはFirebaseコンソールにアクセスします。

https://console.firebase.google.com/

この画面から「プロジェクトを追加」を選択し、プロジェクト名などを入力してプロジェクトを作成します。

プロジェクトの作成
プロジェクトの作成

作成したプロジェクト内に入ったら、ご自分の作成対象アプリケーション(iOS、Android、Web)に合わせてconfigなどを取得します。
今回はWEBを例にします。
対象を選ぶと、config情報などが表示されますのでコピーしましょう。

configの取得
configの取得

内容は以下の通りです。ユーザーごとに書かれている内容(ドメインなど)が異なりますので必ずご自分の環境で表示されたconfigを使用しましょう。

<script src="https://www.gstatic.com/firebasejs/5.7.0/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    authDomain: "xxxxxxxx.firebaseapp.com",
    databaseURL: "https://xxxxxxxx.firebaseio.com",
    projectId: "xxxxxxxx",
    storageBucket: "xxxxxxxx.appspot.com",
    messagingSenderId: "1111111111111111111"
  };
  firebase.initializeApp(config);
</script>

最後に、認証機能を設定します。
認証の設定画面に移動し、ログイン方法を指定します。
今回はメールアドレスとパスワードを使った一般的なログイン方法を使います。

ログイン方法の設定
ログイン方法の設定

「メール/パスワード」の項目をクリックして、設定を有効にします。
有効にしたら保存を忘れずに。

ログイン方法有効化
ログイン方法有効化

もちろんここで、SNS認証の設定もできますが、今回はやりません。
後日やることがあれば追記したいと思います。

Firebaseを使うためにNuxt.js側で設定

上記でコピーしたconfigの内容をNuxt.jsに反映して行きます。
コピーした内容の1行目にある

<script src="https://www.gstatic.com/firebasejs/5.7.0/firebase.js"></script>

は、二通りの方法で導入が可能です。

yarnでfirebaseモジュールを組み込む方法

こちらが一般的ですね。

$ yarn add firebase --save

これを実行すれば、Nuxt.js上では以下のようにfirebaseを呼び出すことが可能になります。

// firebaseのインポート
import firebase from 'firebase'
nuxt.config.jsで読み込む

動作確認はしていないですが、こちらの方法でも可能だと思います。
Nuxt.jsは外部リソースを読み込む際にnuxt.config.jsに定義が必要です。

https://ja.nuxtjs.org/faq/

今回のfirebaseのスクリプトであれば以下のようになります。

module.exports = {
  head: {
    script: [
      { src: 'https://www.gstatic.com/firebasejs/5.7.0/firebase.js' }
    ]
  }
}

これでfirebaseを使う環境は整いました。
早速画面を作成して行きましょう。

認証画面の作成

Nuxt.jsの場合はページの作成には、pagesディレクトリ配下にvueファイルを追加して行きます。

http://www.sky-limit-future.com/entry/nuxtjs_vue_router

今回は全て同じ画面でやるとして、authページを作成します。
もちろん新規登録画面・ログイン画面などを分けてもOKです。

/pages
 ├ index.vue
 └ auth.vue

auth.vue

スタイルは省略しています。

<template>
  <section class="container">
    <div>
      <h1 class="title">
        firebaseでログイン実装しました!
      </h1>
      <section class="ex__box">
        <h5>新規登録</h5>
        <p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
        <p><input type="password" v-model="password" placeholder="パスワード"></p>
        <div class="links">
          <a class="button--green">新規登録</a>
        </div>
      </section>
      <section class="ex__box" >
        <h5>ログイン</h5>
        <p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
        <p><input type="password" v-model="password" placeholder="パスワード"></p>
        <div class="links">
          <a class="button--green">ログイン</a>
        </div>
      </section>
      <section class="ex__box">
        <h5>ログイン中です</h5>
        <div class="links">
          <a class="button--grey">ログアウト</a>
        </div>
      </section>
    </div>
  </section>
</template>

<script>
export default {
  data: function(){
    return {
        mailAddress: '',
        password: '',
    }
  },
  methods: {
  },
}
</script>

今回はクライアント側でのエラーハンドリングなどは省略していますが、本来であれば入力形式のチェックなどはやるべきでしょう。
Firebase Authenticationからエラーが返却されてきた場合だけエラーを出すように実装していこうと思います。

dataとして、メールアドレス、パスワードを用意しています。

ここまでで画面を作成完了です。

認証画面作成
認証画面作成

続いてFirebase Authenticationとの連携部分を作成しましょう。

Firebase Authenticationとの連携

今回はこのようなイメージで作成して行きます。

Firebase Authenticationとの接続イメージ
Firebase Authenticationとの接続イメージ

Firebase Authenticationとの接続はapiディレクトリ配下のUserAPI.jsで行います。
これは私の好みなので、apiディレクトリなしで、次に説明するモジュール内から直接呼ぶ実装でも問題ないと思います。

/api
 └ UserAPI.js

Vuexを使って状態管理を行うので、ユーザー情報を管理するためにuserモジュールを作成します。
Nuxt.jsではstoreディレクトリの配下に「*.js」のファイルを作成するとそれがモジュールとして認識されるので、今回はuser.jsを作成します。

/store
 └ user.js

最後に、先ほど作成したauth.vueで制御を行います。
まずは接続部分を作成します。

UserAPI.jsの作成

apiディレクトリを作り、その配下にUserAPI.jsを作成します。
今回必要な機能は以下の通りです。

・新規ユーザー登録
・ログイン
・ログアウト
・ユーザー情報取得

// firebaseのインポート
import firebase from 'firebase'

export default class UserAPI {

    /**
     * メールアドレスとパスワードで新規ユーザー登録を実施します。
     * @param {string} mailAddress 
     * @param {string} password 
     */
    static regist(mailAddress, password) {
        return firebase.auth().createUserWithEmailAndPassword(mailAddress, password);
    }

    /**
     * メールアドレスとパスワードでログインを実施します。
     * @param {string} mailAddress 
     * @param {string} password 
     */
    static login(mailAddress, password) {
        return firebase.auth().signInWithEmailAndPassword(mailAddress, password);
    }

    /**
     * ログアウトします。
     */
    static logout(){
        return firebase.auth().signOut();
    }

    /**
     * ユーザー情報を取得します。
     */
    static getUser(){
        return firebase.auth().currentUser;
    }

    /**
     * ユーザー情報を取得します。
     */
    static authStateCheck(){
        return firebase.auth().onAuthStateChanged();
    }
}

ユーザー情報の取得に関しては、currentUserとonAuthStateChangedを用意しましたが、ドキュメントを見るとonAuthStateChangedが推奨されているようです。
ここに関しては研究中ですので、とりあえず2つ用意しており、前者を主に使用しています。

userモジュールの作成

storeディレクトリ内にuser.jsを作成して、以下のようにします。
少し長いので分割して解説します。

まずはapiのインポートとstateの定義です。

// UserAPIのインポート
import UserAPI from "../api/UserAPI"

export const state= () => ({
    isLogin : false,
    emailAddress : "",
    authError: ""
})

今回は3つ用意しています。

isLogin : ログイン状態かを判定
emailAddress : メールアドレス
authError : 認証エラー時のメッセージ

次にミューテーションです。

export const mutations =  {
    // ユーザー情報を設定します。
    setEntity (state, user) {
        state.emailAddress = user.email;
    },
    // stateを初期化します。
    clear (state) {
        state.emailAddress = "";
        state.isLogin = false;
        state.authError = "";
    },
    // エラーメッセージを設定します。
    setAuthError (state, authError) {
        state.authError = authError;
    },
    // ログイン状態を設定します。
    setIsLogin (state, isLogin) {
        state.isLogin = isLogin;
    }
}

setEntityは今回はメールアドレスの設定のみですが、今後情報が増えた際に個別に設定するのではなく、ここで設定できるように用意しています。
最後にアクションです。
commitで呼び出している内容は上記のミューテーションで定義したものです。

export const actions =  {
    // ユーザー情報を取得します。
    load: ({ commit }) => {
        var currentUser = UserAPI.getUser();
        if(currentUser) {
            // ログイン済み
            commit('setIsLogin', true);
            commit('setEntity', currentUser);
        } else {
            // 未ログイン
            commit('setIsLogin', false);
            commit('clear');
        }
    },
    // 新規ユーザー登録を行います。
    regist: ({ commit, dispatch }, payload) => {
        return UserAPI.regist(payload.mailAddress, payload.password)
            .then((res) =>{
                commit('setIsLogin', true);
                dispatch('setEntity', res.user);
            })
            .catch(function(error) {
                commit('setIsLogin', false);
                commit('setAuthError', error.message);
                commit('clear');
            });
    },
    // 新規ユーザー登録を行います。
    login: ({ commit, dispatch }, payload) => {
        return UserAPI.login(payload.mailAddress, payload.password)
            .then((res) =>{
                commit('setIsLogin', true);
                dispatch('setEntity', res.user);
            })
            .catch(function(error) {
                commit('setIsLogin', false);
                commit('setAuthError', error.message);
                commit('clear');
            });
    },
    // 新規ユーザー登録を行います。
    logout: ({ commit }) => {
        return UserAPI.logout()
            .then((res) =>{
                commit('setIsLogin', false);
                commit('clear');
            })
            .catch(function(error) {
                commit('setAuthError', error.message);
            });
    },
    // 新規ユーザー登録を行います。
    setEntity: ({ commit }, user) => {
        commit('setEntity', user);
    }
}

以上でモジュールの完成です。

画面への組み込み

最後に画面を作成しましょう。
以下、auth.vueに追記していきます。
まずはログイン状態やエラーメッセージを画面で確認できるようにcomputedを用意します。

computed: {
    isLogin(){
        return this.$store.state.user.isLogin;
    },
    authError(){
        return this.$store.state.user.authError;
    }
},

これを使って画面の出し分けを行います。
新規ユーザー登録とログイン部分は未ログイン時のみ表示し、ログアウト部分はログイン時のみ表示します。
Firebaseからエラーが帰ってきた場合は、その内容が表示されるようにします。
また、ボタンに対してイベントを設定しました。
(追加部分にはコメントを入れました)

<!-- 新規登録に v-if="!isLogin" を追加 -->
<section class="ex__box" v-if="!isLogin">
  <h5>新規登録</h5>
  <p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
  <p><input type="password" v-model="password" placeholder="パスワード"></p>
  <!-- エラーメッセージ表示部分を追加 -->
  <p class="errMessage" v-if="authError">{{authError}}</p>
  <div class="links">
    <!-- クリックイベントを追加 -->
    <a @click="regist()" class="button--green">新規登録</a>
  </div>
</section>

<!-- ログインに v-if="!isLogin" を追加 -->
<section class="ex__box" v-if="!isLogin">
  <h5>ログイン</h5>
  <p><input type="text" v-model="mailAddress" placeholder="メールアドレス"></p>
  <p><input type="password" v-model="password" placeholder="パスワード"></p>
  <!-- エラーメッセージ表示部分を追加 -->
  <p class="errMessage" v-if="authError">{{authError}}</p>
  <div class="links">
    <!-- クリックイベントを追加 -->
    <a @click="login()" class="button--green">ログイン</a>
  </div>
</section>

<!-- ログアウトに v-if="isLogin" を追加 -->
<section class="ex__box" v-if="isLogin">
  <h5>ログイン中です</h5>
  <!-- ログイン中ユーザーのメールアドレスを表示 -->
  <p>メールアドレス:{{$store.state.user.emailAddress}}</p>
  <div class="links">
    <!-- クリックイベントを追加 -->
    <a @click="logout()" class="button--grey">ログアウト</a>
  </div>
</section>

ちなみに、この画面だと新規登録とログインで同じ変数を使っているので、どちらかに入力するともう一方にも反映されます。
本来であれば、画面の表示を片方(新規登録 or ログインどちらか一方しか表示されないよう)にするか、変数を分けるべきでしょう。

最後に、ユーザ新規登録・ログインなどを実行するためのメソッドを用意します。

methods: {
    init(): function() {
        this.password = "";
        this.mailAddress = "";
    },
    regist: function () {
        this.$store.dispatch('user/regist', {mailAddress:this.mailAddress, password:this.password});
        this.init();
    },
    login: function () {
        this.$store.dispatch('user/login', {mailAddress:this.mailAddress, password:this.password});
        this.init();
    },
    logout : function() {
        this.$store.dispatch('user/logout');
    }
}

Vuexの詳細な説明はしませんが、今回作成したuserモジュールのregistアクションを使用するには以下のように書きます。

this.$store.dispatch('user/regist');

以上で、実装完了です。
実際の画面はこちら。

vueproducts-skylimitfuture.firebaseapp.com


随時更新中なので、ここで説明している内容から差異はあるかもしれませんが、基本的な実装は変わりません。
(現在はユーザー名の登録なども可能になっています)

以上です。