質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

Q&A

0回答

949閲覧

【Vue.js】vue-routerのナビゲーションガードでガードできない

eici

総合スコア3

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

0グッド

0クリップ

投稿2021/06/20 07:01

前提・実現したいこと

vue-routerのナビゲーションガードを使用して、認証が必要なページへのアクセスの制限を実装しました。
しかし、ブラウザの新しいタブを開いてURLから認証が必要なページへアクセスすると、アクセスできてしまうという落とし穴を見つけてしまいました。
例えば、私のアプリでは、ログインしている場合はユーザーの新規登録ページ、ログインページにはアクセスできないようにしたいです。しかし、ログインしている状態で、他のページからログインページにアクセスするとナビゲーションガードが実行されて、アクセスできないのですが、ブラウザの新しいタブを開いてurlからログインページにアクセスするとできてしまいます。
この問題を解決したいです。

フォルダ構成

app/javascript ├── app.vue ├── channels │   ├── consumer.js │   └── index.js ├── components │   ├── Flash.vue │   ├── Header.vue │   ├── Home.vue │   └── users │   ├── LogInPage.vue │   └── SignUpPage.vue ├── packs │   ├── application.js │   ├── hello_vue.js │   ├── modules │   │   └── validate_email.js │   ├── plugins │      └── csrf_token_plugin.js │  ├── router.js └── store └── store.js

該当のソースコード

以下、app/javascriptを@で記します。

@/router.js
meta-requiresAuthは、trueなら認証を必要とする、falseなら認証済みではアクセスできない、nullならどちらでも良い、という仕様です。

js

1import Vue from 'vue' 2import store from './store/store' 3import Router from 'vue-router' 4import Home from './components/Home' 5 6Vue.use(Router) 7 8// ルーティング 9const routes = [ 10 // トップページ 11 { 12 path: '/', 13 component: Home, 14 meta: { 15 title: '', // ページ固有のタイトル 16 requiresAuth: null // 認証が必要か? 17 } 18 }, 19 // ユーザー新規登録ページ 20 { 21 path: '/sign_up', 22 component: () => import('./components/users/SignUpPage'), 23 meta: { 24 title: 'アカウント登録', 25 requiresAuth: false 26 } 27 }, 28 // ログインページ 29 { 30 path: '/log_in', 31 component: () => import('./components/users/LogInPage'), 32 meta: { 33 title: 'ログイン', 34 requiresAuth: false 35 } 36 } 37] 38 39const router = new Router({ 40 routes 41}) 42 43// ナビゲーションガード 44router.beforeEach((to, from, next) => { 45 // 認証が必要なページで、ログインしていない場合 46 if (to.meta.requiresAuth && !store.getters.isLoggedIn) { 47 store.dispatch('setFlashMessage', 'このページにアクセスするにはログインする必要があります') 48 next('/log_in') 49 // 認証済みではアクセスできないページで、ログイン済みの場合 50 } else if (to.meta.requiresAuth === false && store.getters.isLoggedIn) { 51 store.dispatch('setFlashMessage', 'このページにはアクセスできません') 52 next(false) 53 // ログインしていても、してなくても大丈夫なページの場合 54 } else { 55 next() 56 } 57}) 58 59export default router 60

@/store/store.js

js

1import Vue from "vue" 2import Vuex from 'vuex' 3 4Vue.use(Vuex) 5 6export default new Vuex.Store({ 7 strict: true, 8 state: { 9 flashMessage: '', // flashの文章 10 currentUser: {} // ログイン中のユーザ 11 }, 12 getters: { 13 getFlashMessage(state) { 14 return state.flashMessage 15 }, 16 // ユーザーがログインしているか? 17 isLoggedIn(state) { 18 return Object.keys(state.currentUser).length !== 0 ? true : false 19 } 20 }, 21 mutations: { 22 // flashメッセージを設定 23 setFlashMessage(state, message) { 24 state.flashMessage = message 25 }, 26 // ログイン中のユーザを設定 27 setCurrentUser(state, user) { 28 state.currentUser = user 29 } 30 }, 31 actions: { 32 setFlashMessage(context, message) { 33 context.commit('setFlashMessage', message) 34 }, 35 setCurrentUser(context, user) { 36 context.commit('setCurrentUser', user) 37 } 38 } 39}) 40

@/app.vue

vue

1<template> 2 <div id="app"> 3 <Header></Header> 4 <Flash></Flash> 5 <router-view></router-view> 6 </div> 7</template> 8 9<script> 10import axios from 'axios' 11import Header from './components/Header' 12import Flash from './components/Flash' 13 14export default { 15 components: { 16 Header, 17 Flash 18 }, 19 methods: { 20 // ページのタイトルを返すメソッド 21 setTitle(routeInstance) { 22 const baseTitle = 'アプリ名' 23 let pageTitle = routeInstance.meta.title 24 if (routeInstance.meta.title) { 25 document.title = pageTitle + ' | ' + baseTitle 26 } else { 27 document.title = baseTitle 28 } 29 } 30 }, 31 mounted() { 32 this.setTitle(this.$route) // ページタイトルを設定 33 // マウント時にストアのログイン中のユーザを設定 34 35 axios.get('/api/logged_in') 36 .then(res => { 37 let user = res.data 38 if (Object.keys(user).length !== 0) { 39 this.$store.dispatch('setCurrentUser', user) 40 } else { 41 this.$store.dispatch('setCurrentUser', {}) 42 } 43 }) 44 .catch(err => { 45 console.log(err) 46 }) 47 }, 48 watch: { 49 // ページが遷移するたびにページタイトルを変更 50 '$route'(to, from) { 51 this.setTitle(to) 52 } 53 } 54} 55</script> 56 57<style scoped> 58p { 59 font-size: 2em; 60 text-align: center; 61} 62</style>

試したこと

@/app.vue のライフサイクルフックを使用してアクセス制限を試みたがだめでした。

vue

1mounted() { 2 this.setTitle(this.$route) // ページタイトルを設定 3 // マウント時にストアのログイン中のユーザを設定 4 let user = {} 5 axios.get('/api/logged_in') 6 .then(res => { 7 user = res.data 8 if (Object.keys(user).length !== 0) { 9 this.$store.dispatch('setCurrentUser', user) 10 } else { 11 this.$store.dispatch('setCurrentUser', {}) 12 } 13 }) 14 .catch(err => { 15 console.log(err) 16 }) 17 // ここから追加 18 // 認証が必要なページで、ログインしていない場合 19 if (this.$route.meta.requiresAuth && Object.keys(user).length === 0) { 20 this.$store.dispatch('setFlashMessage', このページにアクセスするにはログインする必要があります) 21 this.$route.push('/log_in') 22 // ログイン済みではアクセスできないページで、ログイン済みの場合 23 } else if (this.$route.meta.requiresAuth === false && Object.keys(user).length !== 0) { 24 this.$store.dispatch('setFlashMessage', 'このページにはアクセスできません') 25 this.$route.push('/') 26 } 27 },

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問