VueRouterとVuexを用いて認証・ルートの保護を行いたい
概要
ページ構成は以下となります。
- Top
- Login
- Home (要認証)
発生しているエラー
Login完了後、Homeへ遷移する際に、下記エラーが発生します。
Uncaught (in promise) Error: Redirected when going from "/login" to "/home" via a navigation guard.
該当のソースコード
Vue
1# src/components/Header.vue 21 <template> 32 ...略 43 <a href="#" @click.prevent="logout"></a> 54 ...略 65 </template> 76 87 <script> 98 export default { 109 methods: { 1110 logout() { 1211 this.$store.dispatch('logout') 1312 this.$router.push('Login') 1413 } 1514 }, 1615 computed: { 1716 isLoggedIn() { 1817 return this.$store.getters.isLoggedIn 1918 }, 2019 user() { 2120 return this.$store.getters.user 2221 }, 2322 }, 2423 mounted() { 2524 this.$store.dispatch('getUser') 2625 } 2726 } 2827 </script>
Vue
1# src/pages/Login.vue 21 <template> 32 ...略 43 <form action="#" @submit.prevent="login"> 54 ...略 65 <button type="submit">Login</button> 76 </form> 87 ...略 98 </template> 109 1110 <script> 1211 export default { 1312 ...略 1413 methods: { 1514 login() { 1615 axios.post('/api/login', this.formData) 1716 .then(response => { 1817 this.$store.dispatch('getUser') 1918 this.$router.push('Home') 2019 }) 2120 .catch(error => { 2221 this.errors = error.response.data.errors 2322 }) 2423 } 2524 } 2625 } 2726 </script>
Vue
1# src/router.js 21 ...略 32 43 const routes = [ 54 { 65 path: '/', 76 name: 'Top', 87 component: Top, 98 }, 109 { 1110 path: '/home', 1211 name: 'Home', 1312 component: Home, 1413 meta: { requiresAuth: true }, 1514 }, 1615 { 1716 path: '/login', 1817 name: 'Login', 1918 component: Login, 2019 }, 2120 ] 2221 2322 const router = new VueRouter({ 2423 ...略 2524 }) 2625 2726 router.beforeEach((to, from, next) => { 2827 if (to.matched.some(record => record.meta.requiresAuth)) { 2928 if (!store.getters.isLoggedIn) { 3029 next({ name: 'Login', query: { redirect: to.fullPath } }) 3130 } else { 3231 next() 3332 } 3433 } else { 3534 next() 3635 } 3736 }) 3837 3938 export default router
Vue
1# src/store.js 21 ...略 32 43 const state = { 54 isLoggedIn: false, 65 user: {}, 76 } 87 98 const getters = { 109 isLoggedIn: (state) => { return state.isLoggedIn }, 1110 user: (state) => { return state.user }, 1211 } 1312 1413 const mutations = { 1514 setUser (state, payload) { 1615 state.isLoggedIn = payload.isLoggedIn 1716 state.user = payload.user 1817 } 1918 } 2019 2120 const actions = { 2221 getUser ({ commit }) { 2322 axios.get('/api/user') 2423 .then(response => { 2524 commit('setUser', { 2625 isLoggedIn: true, 2726 user: response.data, 2827 }) 2928 }) 3029 .catch(error => { 3130 commit('setUser', { 3231 isLoggedIn: false, 3332 user: {}, 3433 }) 3534 }) 3635 }, 3736 logout ({ commit }) { 3837 axios.post('/api/logout') 3938 commit('setUser', { 4039 isLoggedIn: false, 4140 user: {}, 4241 }) 4342 } 4443 } 4544 4645 const state = new Vuex.Store({ 4746 state, 4847 getters, 4948 mutations, 5049 actions, 5150 }) 5251 5352 export default store
考察・試したこと
ナビゲーションガートを介して「/login」から「/home」に移動する際、リダイレクトされます。
とエラーメッセージにあるので src/router.js 28行目の store.getters.isLoggedIn が false になっている為、/login へリダイレクトされているのではないかと予想し、直前で console.log() で確認してみたところ、予想通り false になっていた。
なぜかと考えた結果、src/pages/Login.vue 17行目の処理が終わる(stateが更新される)前に18行目(routeの移動)が開始されてしまうことが原因と考察。
考察通り、stateが更新された直後と、router.beforeEach が始まった直後に console.log() を仕込んだところ、後者の方が先に出力された。
(stateの更新が完了する前にstateの判定に行ってしまっている。)
困っていること
上記のように原因の予想はついたものの、これを解決する術がわかりません。
stateの更新が完了するまでrouteの移動を待たせる方法があれば一番手っ取り早い解決策となるかと思うのですが、皆さんの知識を貸していただけると幸いです。
また、別のアプローチを用いて認証とルートの保護を行う方法があれば合わせてご教授いただけると幸いです。
以上、よろしくお願いいたします。
あなたの回答
tips
プレビュー