使用環境
Laravel 5.7
jwt-auth 1.0.0-rc3
Vue 2.5
vue-router 3.0
vuex 3.0
この記事は下記の続きです。
Laravel + JWTAuth + Vue.js でAPIログイン認証の実装
ストアの作成
これがないと始まりません、npmでVuexをインストールします。
$ npm install vuex --save
最初にStoreファイルから作成していきましょう。
新たにstore
ディレクトリを作成し、その中にindex.js
を作成します。
resources/js/store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; import auth from "./modules/auth"; import alert from "./modules/alert"; Vue.use(Vuex); export default new Vuex.Store({ modules: { auth, alert } });
今回は認証関係のステートを管理するauth
と、「ログインしました。」みたいなメッセージを表示する用のalert
ストアを作成します。
後々拡張してく予定なので、modules
で分けておきましょう。
次にalert
モジュールから見ていきましょう。
resources/js/store/modules/alert.js
const state = { message: '', // 表示する文字列 type: 'success' // クラス名に使用 }; const mutations = { setAlert (state, {message, type}) { state.message = message; state.type = type || 'success'; } }; export default { namespaced: true, state, mutations };
アラートはサーバーとのやりとりはないのでstate
とmutations
だけです。
resources/js/store/modules/auth.js
import router from '../../router'; const state = { token: '' }; const mutations = { login (state, payload) { state.token = payload; }, logout (state) { state.token = null; } }; const getters = { isLogin (state) { return state.token ? true : false; } }; const actions = { login ({ commit }, payload) { axios.post('/api/login', { email: payload.email, password: payload.password }).then(res => { const token = res.data.access_token; axios.defaults.headers.common['Authorization'] = 'Bearer ' + token; commit('login', token); router.push({path: '/'}); commit('alert/setAlert', { 'message': 'ログインしました。' }, { root: true }); }).catch(error => { commit('alert/setAlert', { 'message': 'ログインに失敗しました。', 'type': 'danger' }, { root: true }); }); }, logout ({ commit }) { axios.post('/api/logout').then(res => { axios.defaults.headers.common['Authorization'] = ''; commit('logout'); router.push({path: '/'}); commit('alert/setAlert', { 'message': 'ログアウトしました。' }, { root: true }); }).catch(error => { commit('alert/setAlert', { 'message': 'ログアウトに失敗しました。' }, { root: true }); }); } }; export default { namespaced: true, state, mutations, getters, actions };
なんかすごいとてつもなくダメな気がしますが、とりあえず今の所こんな感じです。
ルーターの修正
ルーターはあまり変わらないですね。
store.getters['auth/isLogin']
でログイン済みかの確認をしています。
resources/js/router.js
import Vue from 'vue'; import VueRouter from 'vue-router'; import store from './store/index'; import Home from './components/pages/Home'; import Login from './components/pages/Login'; import User from './components/pages/User'; Vue.use(VueRouter); const routes = [ { path: '/', component: Home }, { path: '/login', component: Login }, { path: '/user', component: User, meta: { requiresAuth: true } } ]; const router = new VueRouter({ mode: 'history', routes }); router.beforeEach((to, from, next) => { // ページを切り替えたらアラート削除 store.commit('alert/setAlert', { 'message': '' }); if (to.matched.some(record => record.meta.requiresAuth)) { // ログインしていなかったらログインページにリダイレクト if (store.getters['auth/isLogin'] === false) { next({ path: '/login', query: { redirect: to.fullPath } }); } else { next(); } } else { next(); } }); export default router;
コンポーネントの修正
最初にどのコンポーネントからでもストアをインポートしないで使えるように、app.js
を修正します。
resources/js/router.js
require('./bootstrap'); import Vue from 'vue'; import router from './router'; import store from './store/index'; Vue.component('app', require('./components/App.vue')); const app = new Vue({ store, router }).$mount('#app');
new Vue
でstore
をインジェクトすることで、各コンポーネントからは、this.$store
でストアにアクセスできるようになります。
resources/js/router.js
<template> <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div v-bind:class="'alert alert-' + alertType" v-if="alertMessage">{{ alertMessage }}</div> <ul> <li><router-link to="/">ホーム</router-link></li> <li><router-link to="/login">ログイン</router-link></li> <li><router-link to="/user">ユーザー情報</router-link></li> <li @click="logout">ログアウト</li> </ul> <hr> <router-view></router-view> </div> </div> </div> </template> <script> import { mapActions, mapState } from 'vuex'; export default { computed: mapState('alert', { 'alertMessage': 'message', 'alertType': 'type' }), methods: mapActions('auth', [ 'logout' ]), } </script>
Vuexのmapヘルパーを使用すると、変数やメソッドを使用する感覚でストアとやりとりできるようになります。
resources/js/login.js
<template> <div> <form @submit.prevent="login"> <h1>ログイン</h1> メールアドレス: <input type="email" v-model="email"> パスワード: <input type="password" v-model="password"> <button type="submit" class="btn btn-primary">ログイン</button> </form> </div> </template> <script> import { mapActions } from 'vuex'; export default { data () { return { email: 'admin@example.com', password: '123456', } }, methods: { login() { this.$store.dispatch('auth/login', { email: this.email, password: this.password }); } } } </script>
これでSPA的な認証周りができた感じなので、次回はからはメインとなる機能を作っていきたいと思います。
ここまでのソースコードはGithubに載せてあります。
LaravelTodoSPA