📌

Vue Router で直アクセスを禁止する

2023/07/19に公開

Vue Router における直アクセスの判定について、ほどほどに使う割には記事として残っているのを見かけなかったので、記事にしてみます。
フォームの完了ページや診断の結果ページなど、他のページからページ遷移するけど直アクセスはさせたくない場合に使用できます。

直アクセスの条件

Vue Router で直アクセスするということは、ページ遷移元のページがないということです。
そういった遷移を判定するのに使えるのが START_LOCATION です。
fromSTART_LOCATION と等しい場合に直アクセスとだとみなすことができます。

ユースケース

/hoge は直アクセス可能で、 /fuga は直アクセスさせたくない(Vue Router を使用して他のページからの遷移のみ許可したい)とします。
ベースとなるルート定義は下記のようになります。
namecomponent など、今回の説明に不要な設定は省略しています。)

routes.js
const routes = [
  {
    path: '/hoge',
  },
  {
    path: '/fuga',
  },
]

export default routes

そのルートにアクセスする前に何らかの処理を行いたい場合は beforeEnter を使用します。
今回は /fuga にアクセスする前に、beforeEnter の中で fromSTART_LOCATION と等しいかを判定します。
等しかった場合、つまり /fuga へ直アクセスされた場合は /hoge へリダイレクトします。

routes.js
import { START_LOCATION } from 'vue-router'

const routes = [
  {
    path: '/hoge',
  },
  {
    path: '/fuga',
    beforeEnter: (to, from) => {
      if (from === START_LOCATION) { // 直アクセスだった場合
        return '/hoge' // '/hoge' へリダイレクトする
      }
    },
  },
]

export default routes

直アクセスを禁止したいページが複数ある場合、何度も同じ処理を書くのは面倒です。
なので直アクセス禁止の部分を関数に切り出した方が取り回しがしやすいです。
下記は直アクセス禁止の処理を denyDirectAccess という関数へ切り出し、ルートに /piyo/hogera も追加し、その両方とも直アクセスを禁止にした例です。

routes.js
import { START_LOCATION } from 'vue-router'

/** 直アクセスを禁止する */
function denyDirectAccess(to, from) {
  if (from === START_LOCATION) { // 直アクセスだった場合
    return '/hoge' // '/hoge' へリダイレクトする
  }
}

const routes = [
  {
    path: '/hoge',
  },
  {
    path: '/fuga',
    beforeEnter: denyDirectAccess,
  },
  {
    path: '/piyo',
    beforeEnter: denyDirectAccess,
  },
  {
    path: '/hogera',
    beforeEnter: denyDirectAccess,
  },
]

export default routes

関数化することのもう1つのメリットは、ルートへのアクセス前、つまり beforeEnter の中で他の処理も行いたい場合にも、見通しが良くなります。
beforeEnter に渡す関数を配列にすることで、複数の処理を行うことができます。
下記は /fuga にアクセスした際に、直アクセス判定の他にも別の処理を行う例です。

routes.js
import { START_LOCATION } from 'vue-router'

/** 直アクセスを禁止する */
function denyDirectAccess(to, from) {
  if (from === START_LOCATION) { // 直アクセスだった場合
    return '/hoge' // '/hoge' へリダイレクトする
  }
}

/** 別の処理1 */
function otherProcess1(to, from) {
  // 別の処理1
}

/** 別の処理2 */
function otherProcess2(to, from) {
  // 別の処理2
}

const routes = [
  {
    path: '/hoge',
  },
  {
    path: '/fuga',
    beforeEnter: [denyDirectAccess, otherProcess1, otherProcess2],
  },
]

export default routes

Discussion