Nuxt.js を使った認証ルートの例
Nuxt.js を使うと認証が必要なルートを簡単に作成できます。
アプリケーションにセッション機能を追加するために express
と express-session
を使います。そのために Nuxt.js をプログラムで使う必要があります。
まず依存パッケージをインストールします:
yarn add express express-session body-parser whatwg-fetch
whatwg-fetch
については後ほど述べます。
それから server.js
ファイルを作成します:
const { Nuxt, Builder } = require('nuxt')
const bodyParser = require('body-parser')
const session = require('express-session')
const app = require('express')()
// `req.body` へアクセスするための Body parser
app.use(bodyParser.json())
// `req.session` を作るためのセッション
app.use(session({
secret: 'super-secret-key',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000 }
}))
// POST `/api/login` でログイン、`req.session.authUser` に追加
app.post('/api/login', function (req, res) {
if (req.body.username === 'demo' && req.body.password === 'demo') {
req.session.authUser = { username: 'demo' }
return res.json({ username: 'demo' })
}
res.status(401).json({ error: 'Bad credentials' })
})
// POST `/api/logout` でログアウト、`req.session` から削除
app.post('/api/logout', function (req, res) {
delete req.session.authUser
res.json({ ok: true })
})
// オプションと併せて Nuxt.js をインスタンス化
const isProd = process.env.NODE_ENV === 'production'
const nuxt = new Nuxt({ dev: !isProd })
// No build in production
if (!isProd) {
const builder = new Builder(nuxt)
builder.build()
}
app.use(nuxt.render)
app.listen(3000)
console.log('Server is listening on http://localhost:3000')
また package.json
scripts を更新します:
// ...
"scripts": {
"dev": "node server.js",
"build": "nuxt build",
"start": "cross-env NODE_ENV=production node server.js"
}
// ...
情報: 上の例を動かすためには npm install --save-dev cross-env
を実行する必要があります。もし Windows で開発しているの でない ならば、start
スクリプトから cross-env を削除して、直接 NODE_ENV
をセットすることもできます。
アプリケーションが、ユーザーが認証されているか否かを ページをまたいで 知るためには、グローバルなステート(状態)が必要です。
Nuxt.js が Vuex を使うよう store/index.js
ファイルを作成します:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// `window.fetch()` 用のポリフィル
require('whatwg-fetch')
const store = () => new Vuex.Store({
state: {
authUser: null
},
mutations: {
SET_USER: function (state, user) {
state.authUser = user
}
},
actions: {
// ...
}
})
export default store
Vue
と Vuex
(Nuxt.js に含まれる)をインポートし、コンポーネントで $store
を使うために Vuex を使うことを Vue に伝えます。fetch()
メソッドをポリフィルするために、require('whatwg-fetch')
が必要です(fetch リポジトリを参照してください)。state.authUser
を設定する SET_USER
ミューテーションを作成します。Nuxt.js は nuxtServerInit
と呼ばれる特定のアクションを、引数でコンテキストを渡して呼び出します。したがって、アプリケーションがロードされたとき、サーバーから取得できるデータがストアに既には入れられています。
store/index.js
内に nuxtServerInit
アクションを追加できます:
nuxtServerInit ({ commit }, { req }) {
if (req.session && req.session.authUser) {
commit('SET_USER', req.session.authUser)
}
}
data メソッドを非同期にするために、Nuxt.js はいくつか異なる方法を用意しています。よく知っている方法を選んでください:
Promise
を返却する。Nuxt.js はコンポーネントをレンダリングする前に、プロミスが解決されるのを待ちます。async
/await
プロポーサル を使う。(詳しくはこちらを参照してください)。login
アクションを追加できます。このアクションはログインするためにページコンポーネントから呼び出されます:
login ({ commit }, { username, password }) {
return fetch('/api/login', {
// クライアントのクッキーをサーバーに送信
credentials: 'same-origin',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username,
password
})
})
.then((res) => {
if (res.status === 401) {
throw new Error('Bad credentials')
} else {
return res.json()
}
})
.then((authUser) => {
commit('SET_USER', authUser)
})
}
logout ({ commit }) {
return fetch('/api/logout', {
// クライアントのクッキーをサーバーに送信
credentials: 'same-origin',
method: 'POST'
})
.then(() => {
commit('SET_USER', null)
})
}
ユーザーがアプリケーションで認証されているか否かをチェックするために、ページコンポーネント内で $store.state.authUser
を使うことができます。
認証されたユーザーのみがコンテンツを閲覧できる /secret
ルートを追加してみましょう:
<template>
<div>
<h1>Super secret page</h1>
<router-link to="/">Back to the home page</router-link>
</div>
</template>
<script>
export default {
// データをこのコンポーネントにセットする必要がないため fetch() を使う
fetch ({ store, redirect }) {
if (!store.state.authUser) {
return redirect('/')
}
}
}
</script>
ユーザーが認証されていなかったときは fetch
メソッド内で redirect('/')
が呼び出されます。