Laravel + Vue.js でOauth認証を利用したサンプルSPA構築 [5] Vue画面構築

Laravelのルーティング

api.phpを編集。
リソースコントローラを一度に登録する方法。
Crudメソッドが全て登録される。
URLやパラメータは、以下が詳しい。
https://readouble.com/laravel/5.7/ja/controllers.html#resource-controllers

api.php


// task全体を設定 Route::group(['middleware' => 'auth:api'], function () { Route::resource('task', 'TaskController'); });

webはSPAにするので、
app.blade.phpを表示させるようにしておく。

web.php

Route::get('/', function () {
    return view('app');
});

Auth::routes();

// Route::get('/home', 'HomeController@index')->name('home');

// Route::get('/tasks', 'TaskController@index');
// Route::post('/task', 'TaskController@store');
// Route::delete('/task/{task}', 'TaskController@destroy');

Vue開発

Topをvueに

TOPページからSPAとなるので、Laravel テンプレートの修正。

app.blade.php

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <title>My Oath Apps</title>
        <link rel="stylesheet" href="{{ mix('/css/app.css') }}">
    </head>
    <body>

      <div id="app"></div>
      <script src=" {{ mix('js/app.js') }} "></script>    

    </body>
</html>

モジュールインストール

router, vuexを使うので、インストールしておく。
※laravelに同梱されていないので

$ npm install vuex --save-dev
$ npm install vue-router --save-dev

storeは、一旦app.jsに書く。

routerは別ファイルとする。

resorce/js/router/index.js

Vue routing

Task Crudと、ユーザー登録、ログインのルーティングを行う。
今回は、下の6つを用意した。
Login
Register
TaskIndex
TaskView
TaskCreate
TaskEdit

Storeを実装

ログイン周りをstoreで管理することに。
TokenはLocalStrageで管理する。
各APIを叩くactionは、非同期通信の制御をしやすくするため、promiseを利用。
login, register の他、状態を確認してtokenを更新するためのcheckLoginStatusも用意することにした。

const store = new Vuex.Store({
  state: {
    isLoggedIn: false,
  },
  mutations: {
    setLogInStatus(state, status) {
      state.isLoggedIn = status
    }
  },
  actions: {

    login({commit, dispatch, state, rootState, getters, rootGetters}, formParams) {
      const self = this
      return new Promise((resolve, reject) => {
        axios.post('/oauth/token', params)
          .then(function (response) {
            // tokenをlocalstrageに格納
            commit('setLogInStatus', true)
          })
          .catch(function (error) {
            commit('setLogInStatus', false)
            resolve(self.getters.getLoginStatus)
          })
      })
    },

    checkLoginStatus ({commit, dispatch, state, rootState, getters, rootGetters}) {
        return new Promise((resolve, reject) => {
          axios.post('/oauth/token', params)
            .then(function (response) {
              // tokenをlocalstrageに格納
              commit('setLogInStatus', true)
            })
            .catch(function (error) {
              commit('setLogInStatus', false)
              window.localStorage.removeItem(self.state.strageKey)
              resolve(self.getters.getLoginStatus)
            })

        })
      }
    },

    logout({commit, dispatch, state, rootState, getters, rootGetters}) {
      // logout
      commit('setLogInStatus', false)
    },

    signup({commit, dispatch, state, rootState, getters, rootGetters}, formParams) {
      const self = this
      return new Promise((resolve, reject) => {
        axios.post('/api/registerhoge', params)
          .then(function (response) {
            // tokenを取得してログイン状態をキープ
          })
          .catch(function (error) {
            commit('setLogInStatus', false)
            resolve(self.getters.getLoginStatus)
          })
      })

    },


  },
  getters: {
    getLoginStatus(state) { return state.isLoggedIn }
  }
})

CRUD実装

各コンポーネントを実装していく。
TASKについては、シンプルなものなので詳細は割愛。

特定のURLでアクセスされた場合のログイン状態の確認について少し悩んでいる。
create()でstoreをwatchすることで状態監視をしているのだが、もっと良い方法はありそう。

    created() {
      const self = this
      let id = self.$route.params.id
      // このページからロードした場合は、mountedのタイミングでは isLoggedIn = falseのはず
      // これは二度目以降に呼ばれた時用。
      if (this.$store.getters.getLoginStatus) {
        self.getTask(id)
        .then( function(response) {
          self.task = response
          self.task_name = self.task.name
          self.task_id = self.task.id
        })
      } else {
        // このページからロードされた場合、ログイン状態の確認をしてから、apiを投げる必要がある。
        // createdの時点では、checkLoginStatusがまだ動かない
        // watchで、state.isLoggedInの状態を監視できる
        // isLoggedIn === trueになった場合に、getTaskできる
        this.$store.watch(
              state => state.isLoggedIn,
              isLoggedIn => {
                if (isLoggedIn) {
                  self.getTask(id)
                  .then( function(response) {
                    self.task = response
                    self.task_name = self.task.name
                    self.task_id = self.task.id
                  })                
                }
              }
            )
      }


    },