Vuexを使って
いい感じにjwt認証を実装してみた
2019/09/18 v-kansai Vue.js/Nuxt Meetup #10
Motoyasu Meguro
趣味は自転車
@mm-git
@wRoute
滋賀県草津市
主な業務内容
I'm a software engineer.
(mapboxを使った地図アプリです)
Route GPXコマ地図エディタ
App storeにて販売中
ログインしたらTODOリストが見れるアプリ
を例にお話しします。
https://github.com/mm-git/vuex-jwt-sample
https://github.com/mm-git/auth-sample-jwt
出典 [https://vuex.vuejs.org/ja/] vuexとは何か
ID, password
jwt
※ホテルのチェックインで名前を言うと、チェックアウトまで有効なカードキーをもらうようなイメージ
〇
〇
ピリオドで3パートに区切られている
{
"uid":"test",
"exp":1568042806,
"jti":"d04a53b6-1087-4c14-b0b1-bd47c78a8d47",
"iat":1568042786,
"iss":"auth-sample-jwt",
"sub":"AccessToken"
}
↓base64デコード
ユーザID
有効期限
・・・というのが今日のお話
複数個所で使うデータを一元管理したい
今回の例だとログインしているのかの状態とjwtのデータを1つのストアで管理したい。
コンポーネント側にバックエンドとのやり取りを書きたくない
ログイン認証の処理をSFCには書きたくない。
devtoolsで状態を確認しやすい
・・とわかりやすいです。
Tips !!
stateやactionsのファイルをimportして
それらをexport defaultしているだけ
export defaultにstateやactionsの中身を書いていく
Tips !!
ログインしているかどうか
トークンのpayload
トークンの有効期限
stateから算出できるものはgettersに記載。
Tips !!
mutaionsで定義する関数の名前(=状態)は、
あらかじめconstで定義しておくと便利。
mutationsの各関数は、mutation-types.jsで定義したconstを使って書いていく。
['文字列']で関数が定義できるのが、最初理解できませんでした・・・
Tips !!
Tips !!
Vuex.storeのmodulesに
作ったストアを追加していく
vuex-persistedstateプラグイン
永続化したいストア全体または
ストアのstateを追加する。
Vuexにログイン処理のほとんどが書かれているので
VuexのmapXXXXヘルパ関数
ストアのactionやstateなどを、あたかもこのコンポーネントに定義したmethodsやpropsの様に扱うことができる。
Tips !!
のかわりに
this.$store.dispatch('auth/login', ...)
this.login()
だけでストアのactionを実行することができる。
ストアのlogin()の結果をawaitで待つことで、ログインの成功/失敗を判定できる。
Tips !!
awaitでログイン結果が待てるので、watch:でauthのstatusを監視する様なことは不要。
TODOのリストをサーバから取得する処理も、Vuexに分離する
TODOリストのコンポーネントの処理はこれだけ!!
methods: {
...mapActions('todoList', ['fetch']),
},
computed: {
...mapState('todoList', ['todoList'])
},
async created () {
await this.fetch()
},
import Vue from 'vue'
import * as types from './mutation-types'
export default {
async fetch (action) {
const res = await action.dispatch('auth/refresh', {}, { root: true })
if (!res) {
return false
}
action.commit(types.REQUESTING)
const accessToken = action.rootState.auth.accessToken
//以下 axiosを使ったGET処理
:
}
}
Tips !!
トークンが必要な処理の直前でauthのrefresh()を実行
authストアの
アクセストークンを使用
すでにログイン済みの状態でログイン画面にアクセスした場合。
Tips !!
:
import store from './store'
Vue.use(Router)
const guardLogin = (to, from, next) => {
if (!store.getters['auth/isAuthenticated']) {
next()
return
}
next('/list')
}
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'login',
component: Login,
beforeEnter: guardLogin
},
:
]
}
↓
beforeEnterでTODOリスト画面へ移動させることができます。
・・・もちろんその逆も。
詳細はコード参照。
トークンの有効期限がきれたら、timeout画面へ移動
Tips !!
export default {
name: 'app',
computed: {
...mapState('auth', ['status'])
},
watch: {
status (newStatus) {
if (newStatus === 'token_expired') {
this.$router.push('/timeout')
}
}
}
}