いつもお世話になっております。
NuxtでJWTを利用したログイン認証の勉強をしているのですが、
ページを開いて初回ログイン後のUser情報取得で認証エラーが発生してしまいます。
ログイン画面
エラー内容
流れとしては、
ログイン時(store/auth.js/login()
)に返ってきたトークンを即時ローカルストレージに保存し、
axiosの通信時にリクエストヘッダーに自動でトークンを付与するように設定。
その後、User情報(store/auth.js/reload()
)を取得しようとしているのですが、
ページを開いて初回ログインボタン押下後は必ずUser情報を取得しようとすると401(認証エラー)が発生します。
もう一度ログインボタンを押すと、問題なくUser情報の取得が可能です。
また、一度ログアウトを押して、ローカルストレージに保存しているトークンを削除後、
再度ログインボタンを押下すると問題なくUser情報の取得が可能です。
手順 | 結果 |
---|---|
ページを開いて初回「ログインボタン押下」 | 401エラー |
2回目以降「ログインボタン押下」 | 正常終了 |
ログアウトボタン押下後、「ログインボタン押下」 | 正常終了 |
エラー自体は、store/auth.js/reloao()
に記述している this.$axios.get( URL )
で発生しているのですが、
なぜ初回のみエラーが出るのかがわかりません。
どなたか原因が分かる方がいらっしゃったらご教授いただけると幸いです。
宜しくお願い申し上げます。
ソースコード
plugins/axios.js
javascript
1export default function( {store, $axios} ){ 2 3 $axios.onRequest( ( config ) => { 4 5 const token = localStorage.getItem( 'access' ) 6 7 if ( token ){ 8 9 console.log( "" ); 10 console.log( "$axios.setToken 実行!" ); 11 12 $axios.setToken( token, 'JWT' ) 13 14 } else { 15 console.log( "" ); 16 console.log( "localStorageにtokenがありません! たぶん初回(アクセストークン取得時)! 初回はreload()がなぜか失敗する!" ); 17 } 18 19 } ) 20 21 22 $axios.onResponse( response => { 23 return Promise.resolve( response ); 24 } ) 25 26 27 $axios.onError( error => { 28 29 30 let messages; 31 32 if ( error.response.status === 400 ){ 33 34 35 /* バリデーションエラー */ 36 console.log( "バリデーションエラー" ); 37 38 let messages = [].concat.apply( [], Object.values( error.response.data ) ) 39 store.dispatch( 'message/setWarningsMessages', {messages: messages} ) 40 41 42 } else if ( error.response.status === 401 ){ 43 44 45 /* 認証エラー */ 46 console.log( "認証エラー" ); 47 48 const token = localStorage.getItem( 'access' ) 49 50 if ( token != null ){ 51 messages = 'ログイン有効期限切れ' 52 } else { 53 messages = '認証エラーです。' 54 } 55 56 console.log( "$axios.onError で auth/logout()実行!" ); 57 58 store.dispatch( 'auth/logout' ) 59 store.dispatch( 'message/setErrorMessages', {messages: messages} ) 60 61 62 } else if ( error.response.status === 403 ){ 63 64 65 /* 権限エラー */ 66 console.log( "権限エラー" ); 67 68 messages = '権限エラーです。' 69 store.dispatch( 'message/setErrorMessages', {messages: messages} ) 70 71 72 } else if ( error.response.status === 500 ){ 73 74 75 /* その他のエラー */ 76 console.log( "その他のエラー" ); 77 78 messages = '想定外のエラーです。' 79 store.dispatch( 'message/setErrorMessages', {messages: messages} ) 80 81 82 } 83 84 return Promise.reject( error.response ); 85 86 } ) 87 88}
store/auth.js
javascript
1export const state = () => ( { 2 3 username: '', 4 authenticated: false 5 6} ) 7 8 9export const getters = { 10 11 username: state => state.username, 12 authenticated: state => state.authenticated, 13 14} 15 16 17export const mutations = { 18 19 set: ( state, payload ) => { 20 21 state.username = payload.user.username 22 state.authenticated = true 23 24 console.log( '[state.username] : ' + state.username ); 25 console.log( '[state.authenticated] : ' + state.authenticated ); 26 27 }, 28 29 30 clear: ( state ) => { 31 32 state.username = '' 33 state.authenticated = false 34 35 }, 36 37} 38 39export const actions = { 40 41 /* ログイン */ 42 login( context, payload ){ 43 44 const params = new URLSearchParams(); 45 46 params.append( 'username', payload.username ); 47 params.append( 'password', payload.password ); 48 49 50 const URL = '/auth/jwt/create/' 51 52 this.$axios.post( URL, params ) 53 .then( res => { 54 55 // 認証用トークンをlocalStorageに保存 56 localStorage.setItem( 'access', res.data.access ) 57 58 context.dispatch( 'reload' ).then( user => user ) 59 60 } ) 61 }, 62 63 64 /* ログアウト */ 65 logout( context ){ 66 67 localStorage.removeItem( 'access' ) 68 context.commit( 'clear' ) 69 70 }, 71 72 73 /* ユーザー情報更新 */ 74 reload( context ){ 75 76 const URL = '/auth/users/me/' 77 78 return this.$axios.get( URL ).then( ( res ) => { 79 80 const user = res.data 81 82 context.commit( 'set', {user: user} ) 83 return user 84 85 } ) 86 87 } 88 89}
pages/index.vue
html
1<template> 2 <div> 3 4 <input v-model="form.username" placeholder="username"> 5 <input v-model="form.password" placeholder="password" type="password"> 6 7 <button @click="login">ログイン</button> 8 <button @click="logout">ログアウト</button> 9 10 </div> 11</template> 12 13<script> 14export default { 15 16 data(){ 17 return { 18 19 form: { 20 username: '', 21 password: '', 22 } 23 24 } 25 }, 26 27 28 methods: { 29 30 async login(){ 31 await this.$store.dispatch( 'auth/login', this.form ) 32 }, 33 34 async logout(){ 35 await this.$store.dispatch( 'auth/logout' ) 36 } 37 38 } 39 40} 41</script> 42 43<style> 44input { 45 border : 1px solid #ccc; 46 border-radius : 5px; 47 display : block; 48 padding : 3px; 49 margin-bottom : 10px; 50} 51</style>
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/10 14:43