title | description | github | livedemo | liveedit |
---|---|---|---|---|
Authentification de routes |
Exemple d'authentification de routes avec Nuxt.js |
auth-routes |
Nuxt.js peut être utilisé pour créer facilement des routes authentifiées.
Pour ajouter la fonctionnalité de sessions dans notre application, nous utiliserons express
et express-session
. Pour cela, nous devons utiliser Nuxt.js de manière programmatique.
Premièrement, nous installons les dépendances :
yarn add express express-session body-parser whatwg-fetch
Nous parlerons de whatwg-fetch
plus loin.
Puis nous créons notre server.js
:
const { Nuxt, Builder } = require('nuxt')
const bodyParser = require('body-parser')
const session = require('express-session')
const app = require('express')()
// Analyse du corps de requête pour y accéder via `req.body`
app.use(bodyParser.json())
// Mise en place de sessions pour y accéder via `req.session`
app.use(session({
secret: 'super-secret-key',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000 }
}))
// Accès à `/api/login` en POST pour connecter l'utilisateur et l'ajouter à `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' })
})
// Accès à `/api/logout` en POST pour déconnecter l'utilisateur et le retirer de `req.session`
app.post('/api/logout', function (req, res) {
delete req.session.authUser
res.json({ ok: true })
})
// Nous instancions Nuxt.js avec les options
const isProd = process.env.NODE_ENV === 'production'
const nuxt = new Nuxt({ dev: !isProd })
// Pas de build en 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')
Et nous modifions nos scripts dans package.json
:
// ...
"scripts": {
"dev": "node server.js",
"build": "nuxt build",
"start": "cross-env NODE_ENV=production node server.js"
}
// ...
Note : vous devrez exécuter npm install --save-dev cross-env
afin de faire fonctionner l'exemple précédent. Si vous n'êtes pas en train de développer sur Windows, vous pouvez laisser cross-env en dehors de votre script start
et définir NODE_ENV
directement.
Nous avons besoin d'un état global pour informer notre application si l'utilisateur reste connecté entre les pages.
Pour laisser Nuxt.js utiliser Vuex, nous créons un fichier store/index.js
:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// Polyfill pour `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
- Nous importons
Vue
etVuex
(inclus dans Nuxt.js) et nous indiquons à Vue d'utiliser Vuex afin de pouvoir utiliser$store
dans nos composants. - Nous utilisons
require('whatwg-fetch')
afin d'obtenir un polyfill pour la méthodefetch()
pour tous les navigateurs (consultez le dépôt fetch). - Nous créons notre mutation
SET_USER
qui va instancierstate.authUser
avec l'utilisateur connecté. - Nous exportons notre instance du store vers Nuxt.js afin qu'il puisse l'injecter dans notre application principale.
Nuxt.js appellera une action spécifique nommée nuxtServerInit
avec le contexte comme argument. Ainsi, lorsque l'application sera chargée, le store sera déjà rempli avec certaines données que nous pouvons obtenir du serveur.
Dans notre store/index.js
, nous pouvons ajouter l'action nuxtServerInit
:
nuxtServerInit ({ commit }, { req }) {
if (req.session && req.session.authUser) {
commit('SET_USER', req.session.authUser)
}
}
Pour rendre la méthode de données asynchrone, Nuxt.js vous offre différents moyens, choisissez celui avec lequel vous êtes le plus à l'aise :
- Retourner une
Promise
, Nuxt.js attendra la résolution de la promesse avant d'afficher le composant. - En utilisant
async
/await
(en savoir plus).
Nous ajoutons une action login
qui sera appelée à partir de nos composants de pages pour connecter l'utilisateur :
login ({ commit }, { username, password }) {
return fetch('/api/login', {
// Envoie les cookies client au serveur
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', {
// Envoie les cookies au serveur
credentials: 'same-origin',
method: 'POST'
})
.then(() => {
commit('SET_USER', null)
})
}
Ensuite, nous pouvons utiliser $store.state.authUser
dans nos composants de pages pour vérifier si l'utilisateur est connecté ou non dans notre application.
Ajoutons une route /secret
dont le contenu ne peut être vu que par un utilisateur connecté :
<template>
<div>
<h1>Page super secrète</h1>
<router-link to="/">Retour à l'accueil</router-link>
</div>
</template>
<script>
export default {
// Nous utilisons`fetch()` car nous n'avons pas besoin d'associer les données à ce composant
fetch ({ store, redirect }) {
if (!store.state.authUser) {
return redirect('/')
}
}
}
</script>
Nous pouvons voir dans la méthode fetch
que nous appelons redirect('/')
lorsque notre utilisateur n'est pas connecté.