こまどブログ

技術のこととか仕事のこととか。

Vue Routerのナビゲーションガードによるアクセス制限を試した&コードを読み解いた

前回の記事に引き続き、Vue Routerについての記事となります。

ky-yk-d.hatenablog.com

Vue Routerでアクセス制限を実現する

今回は、ナビゲーションガードを利用したアクセス制限を実現するコードを解読していきます。実現したいのは、「特定のパスに対してアクセス制限をかける」ことです。

今回は、コードの中核部分を『基礎から学ぶVue.js』(およびそのサポートページ)に負っています。初心者にわかりやすく、また実践的でもあり、そしてサポートページが実に充実している書籍です。ありがたい。

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

今回のコードを置いているGitHubリポジトリはこちら(すでに更新が加わっています)。このリポジトリに限らず、コードの書き方等に指摘あればぜひお知らせください!

github.com

Vue Routerの設定とナビゲーションガードの導入

前回、Vuer Routerの設定は以下のようにしていました。

let router = new VueRouter({
  routes: [
    {
      path: '',
      component: Top,
      children: [
        {
          path: '',
          component: ChildA,
          name: 'childA'
        },
        {
          path: '/childB',
          component: ChildB,
          name: 'childB',
          meta: {
            requiresAuth: true
          }
        }
      ]
    },
    {
      path: '/helloworld/:msg',
      component: HelloWorld,
      name: 'helloworld'
    }
  ]
});

/childBというパスに対して、meta要素にrequiresAuth: trueを指定しています。この要素を利用して、認証が必要なパスと不要なパスとを区分していきます。

ナビゲーションガード(グローバルガード)のコード

ナビゲーションガードを導入します。利用するのは「グローバルガード」です。

今回記載したソースコードは下記のようなものです。こちら、ほぼ『基礎から学ぶVue.js』記載のコードとなっています。

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (!store.state.isLogin) {
      next({
        path: '/',
        query: {
          redirect: to.fullPath
        }
      })
    } else {
      next();
    }
  } else {
    next(); 
  }
});

このコードを読み解いてみます。

Vue Routerの様々なオブジェクト

router.beforeEach()は、ルーターインスタンスのメソッドで、画面遷移前に実行される処理を引数に記載します。処理の中では、遷移先をnext()で指定します。上の例の場合、一定の条件下でリダイレクトさせるために利用しています。

次に、ifの条件となっているto.matched.some(record => record.meta.requiresAuth)についてです。toは、遷移先を示すルートオブジェクトです。単なる文字列ではありません。公式ドキュメントの記述を引用します。

遷移先のURLの、現在の URL をパースした情報と、その URL とマッチしたルートレコードを保持しています。ルートレコードはroutes設定の配列 (とchildren配列) 内のオブジェクトのコピーです。

matchedは、ルートポブジェクトのプロパティで、この「現在のルートのネストされた全パスセグメントに対しての ルートレコード を保持している配列」です。

この場合、VueRouterのコンストラクタに渡しているオブジェクトのroutes配列の1つ目の要素(path: ''の部分)と、その中のchildren配列の2つ目の要素(path: '/childB'の部分)とを要素とする配列ということになります。

Array.prototype.some()

そして、some()メソッドはArray.prototype.some()です。

developer.mozilla.org

some()メソッドは、to.matchedという配列の各要素をそれぞれrecordとして扱い、record.meta.requiresAuthが真となる要素があれば真を返します。今回の場合、childB側の要素が条件に合致するため、some()メソッドが真を返し、認証の確認部分が実行されるというわけですね。

※今回の例では、requiresAuth: trueと指定しているchildBがネストの最下位ですが、some()を利用することで、上位のパスにrequire sAuth: trueを指定されていれば認証確認の対象となります。

認証の確認とリダイレクト、そしてVuexへ

認証確認部分はシンプルです。if(!store.state.isLogin)でログインしているかどうかを確認し、ログインしていなければnext()の引数(ルートオブジェクト)で認証不要なパスを指定します。上記の例では、クエリ文字列でリダイレクト元(本来の、許可されなかった遷移先)の情報を付加しています。

f:id:ky_yk_d:20180707184943p:plain

以上によって、「特定のパスにアクセス制限をかける」ことが実現できました。そのまま使えるサンプルコードや、親切な解説書の存在はとてもありがたいですが、その先で自力でAPIドキュメントを読んでみると、理解度が全然違いますね。Array.prototype.some()も、今回はじめて知りました。

今回は、Vue Routerのナビゲーションガードを用いて特定のパスにアクセス制限をかけてみました。今回用いたのはグローバルガードと呼ばれる最も基本的なナビゲーションガードでしたが、他の種類のナビゲーションガード、あるいはナビゲーションガード以外のVue Routerの機能も少しずつ試していきたいと思います。

また、ちらっと登場したstore.state.isLoginは、実はVuexを利用しています(アクセスの仕方がこれでいいのかは不明・・・)。まだVuexは消化不良なのですが、ある程度の段階で記事にまとめようと思います!

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js