Nuxt.js_Vuexの永続化
Nuxt Vuexの永続化
Vuexとは
Vuexとは、Vueアプリケーションで使用する状態管理ライブラリです。
コンポーネント間でのデータ受け渡しを効率化する(アプリケーション上のどこからでもアクセスできる)ための仕組みとなります。
ただし、Vuex にアプリケーションの状態を保存しても、リロードしたタイミングでデータはリセットされてしまいます。
APIトークンなどの永続保持したい用途には対応できません。
vuex-persistedstateについて
vuex-persistedstate は Vuex Store のデータを localstorage に自動的に格納させるためのライブラリです。
vuex-persistedstateを使うとVuexのステート情報はブラウザのlocalStorageを使って永続化されます。
この仕組みにより、ブラウザのリロード時もVuexのステート情報を保持することができます。
vuex-persistedstateのインストール
Nuxtプロジェクトフォルダで、下記コマンドを実行します。
$ npm install vuex-persistedstate --save
APIトークンの保持
REST APIで認証トークンを取得し、vueページで任意に利用する例です。
ここでは、AcccessToken、IDToken、RefreshTokenの3トークンを扱います。
Storeファイルを作成する。
store/index.jsを用意します。
assets/config.jsonにURLやclientIDなどを記載しています。
import createPersistedState from 'vuex-persistedstate'
import config from '~/assets/config.json'
const axios = require('axios')
export const state = () => ({
idToken: null,
accessToken: null,
refreshToken: null,
loginDate: null
})
export const mutations = {
setLogin(state, info) {
state.idToken = info.idToken
state.accessToken = info.accessToken
state.refreshToken = info.refreshToken
state.loginDate = new Date()
},
setLogout(state) {
state.idToken = null
state.accessToken = null
state.refreshToken = null
state.loginDate = null
},
setRefreshToken(state, info) {
state.idToken = info.idToken
state.accessToken = info.accessToken
state.loginDate = new Date()
}
}
const localMethods = {
isTokenExpired(preLoginDate) {
const preDate = new Date(preLoginDate)
const nowDate = new Date()
// 一時間を超えているか判定する。
if ((nowDate.getTime() - preDate.getTime()) > (60 * 60 * 1000)) {
return true
}
return false
}
}
export const actions = {
isLoggedIn(context) {
try {
if ((!context.state.idToken) || (!context.state.accessToken)) {
return false
}
if (!context.state.refreshToken) {
return false
}
if (localMethods.isTokenExpired(context.state.loginDate)) {
// The token is already expired.
return false
}
return true
} catch (error) {
return false
}
},
async login(context, { username, password }) {
try {
const url = config.ApiUrl + '/login'
const headers = { 'Content-Type': 'application/json;charset=UTF-8' }
const data = {
'username': username,
'password': password,
'poolId': config.poolId,
'clientId': config.clientId
}
const res = await axios.post(url, data, { headers: headers })
context.commit('setLogin', res.data)
} catch (error) {
throw error
}
},
async logout(context) {
try {
if (localMethods.isTokenExpired(context.state.loginDate)) {
// The token is already expired.
return
}
const url = config.ApiUrl + '/logout'
const axiosInstance = axios.create({
headers: {
'Authorization': context.state.accessToken
}
})
await axiosInstance.post(url)
context.commit('setLogout')
} catch (error) {
throw error
}
},
async refreshToken(context) {
try {
if (localMethods.isTokenExpired(context.state.loginDate) === false) {
return
}
const url = config.ApiUrl + '/refresh'
const headers = { 'Content-Type': 'application/json;charset=UTF-8' }
const data = {
'clientId': config.clientId,
'refreshToken': context.state.refreshToken
}
const res = await axios.post(url, data, { headers: headers })
context.commit('setRefreshToken', res.data)
} catch (error) {
throw error
}
}
}
export const plugins = [
createPersistedState()
]
Storeを参照する。
pages/login.vueからログインを実行してトークンをstoreに保存します。
<template>
...(略)
</template>
<script>
export default {
data: () => ({
username: '',
password: ''
}),
methods: {
execLoginAPI: async function () {
try {
await this.$store.dispatch('login', {
username: this.username,
password: this.password
})
return true
} catch (e) {
return false
}
}
}
}
</script>
ログアウトする場合は下記のように定義します。
logout: async function () {
try {
await this.$store.dispatch('logout')
} catch (e) {
console.log(e)
}
this.$router.replace('/')
}
トークンを用いて他のAPIを実行する場合には下記のように定義します。
execUpdateAPI: async function () {
try {
await this.$store.dispatch('refreshToken')
const url = config.ApiUrl + '/data/' + String(this.item.id)
const headers = {
'content-type': 'application/json',
'Authorization': this.$store.state.idToken
}
const putBody = {
'accessToken': this.$store.state.accessToken,
'data': this.updatedata,
}
await axios.put(url, putBody, { headers: headers })
return true
} catch (error) {
this.setErrorMessage(error)
return false
}
}