ミドルウェアを使ってNuxtプロジェクトの特定ページに認証機能を導入する


SPAアプリケーションを開発していて特定のページは条件次第で表示させず、トップ画面に戻したいとかあると思います。

Angularにはガードという機能が標準で提供されています。特定のページに対して遷移前にチェックを挟むことができます。
Qiita Angularのルーティング設定(応用編)

Nuxt.jsではそれっぽい名前のものがなさそうですが、ミドルウェアという機能を使えば実現できそうです。
Nuxt.js公式ドキュメント

ミドルウェアを使うと、特定のページやいくつかのページのグループがレンダリングされる前に実行されるカスタム関数を定義することができます。

環境

  • Nuxt.js v2.14.0 SPAモード

ユニバーサルモードとSPAモードではミドルウェアの挙動が違います。
本記事ではSSRの挙動は確認していません。

ユニバーサルモードの場合、ミドルウェアはサーバサイドでは一度だけ呼び出され(Nuxt アプリケーションへの最初のリクエスト時、またはページの再読込み時)クライアントサイドでは他のルートへ移動したときに呼び出されます。ページを静的に生成しているときは、ミドルウェアはサーバーサイドではなくビルド時に一度だけ呼び出されます。SPA モードの場合、ミドルウェアはクライアントサイドで最初のリクエスト時と他のルートへ移動したときに呼び出されます。

実装

ミドルウェアファイルの作成

ミドルウェアとして使用するファイルはmiddlewareフォルダに置く必要があります。
テストなので半分の確率でログイン画面にリダイレクトするようにしています。実際にアプリを作成する際は、ストアなどから情報を取得して判定します。

middleware/guard.js
export default function ({ redirect }) {

    if (Math.random() > 0.5) {
        return redirect('/login');
    }
}

ミドルウェアの利用

export defaultmiddlewareにファイル名を指定することで利用できます。
これでprotectページが開く前(レンダリング前)にミドルウェアの処理が割り込まれるようになります。

pages/protect.vue
<template>
  <div>
    <div>protect-page</div>
    <img src="~/assets/img/secret.jpeg">
  </div>
</template>
<script>
import Vue from 'vue'
export default {
  middleware: 'guard',
}
</script>

動作検証

ホーム画面からprotectページに遷移した際にミドルウェアが動作するか検証します。

ミドルウェアによるチェックをパスした場合

通常通りページ遷移を行います。

ミドルウェアのチェックにひっかかった場合

protectページへの遷移がキャンセルされて、ログインページにリダイレクトします。

この場合にprotectページのブラウザ履歴はありません。リソースの読み込みも発生しません。
home→loginという遷移が行われたことになっており、ブラウザバックするとhomeに戻ります。

直接URL窓にガード対象のページパスを打ち込んだ場合

直接URL窓に打ち込んだ場合でも、protectページのレンダリング前にミドルウェアは動作しログイン画面に遷移しました。

余談

Vue Routerのナビゲーションガードを使って、ガードする方法もあるみたいですが、直接URL打ち込んだ場合に動かずprotectページが表示されてしまったので、Vue Routerのナビゲーションガードは使用しないことにしました。※うまくやればできる?

記述量が少なく、とてもシンプルに実装できたので、特に問題なければこの方法でフロント側のナビゲーションチェックしようと思います。