博客的后台管理页面须要有登陆系统,因此考虑作一下路由鉴权,实现方式也是 Nuxt 官网给出栗子来改写,顺便也将先后端路由给统一了。前端
前端方面主要经过利用 Nuxt 的中间件来作路由拦截,这里也是须要 Vuex 状态树来作。vue
middleware/auth.js
复制代码
export default function ({ store, redirect }) {
if (!store.state.user) {
return redirect('/login')
}
}
复制代码
经过对状态树上的用户信息是否存在来鉴权,来对页面进行重定向mongodb
layouts/admin.vue
复制代码
export default {
middleware: 'auth',
components: {
AdminAside
}
}
复制代码
在后台管理系统的页面布局上添加 中间件npm
在 NuxtJs 的渲染流程中,当请求打入时,最早调用的便是 nuxtServerInit 方法,能够经过这个方法预先将服务器的数据保存。json
咱们能够利用该方法来接收存储用户信息的 Session 信息。segmentfault
nuxtServerInit ({ commit }, { req, res }) {
if (req.session && req.session.user) {
const { username, password } = req.session.user
const user = {
username,
password
}
commit('SET_USER', user)
}
},
复制代码
当应用完毕时,一些咱们从服务器获取到的数据就会被填充到这个状态树 (store) 上。后端
按照 NuxtJs 官网给出的栗子来看,到这里基本算把页面中路由鉴权部分写完了,接下来是对服务器端该部分代码的写做api
后端代码我采用是 Koa 框架,以及 koa-session 来对Session作处理。promise
在新建 nuxt 项目的时候直接选用 Koa 框架便可bash
vue init nuxt/koa
复制代码
相关依赖
npm install koa-session
复制代码
在 server.js 中改写
import Koa from 'koa'
import { Nuxt, Builder } from 'nuxt'
// after end
import session from 'koa-session'
async function start () {
const app = new Koa()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 7998
// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(app.env === 'production')
// Instantiate nuxt.js
const nuxt = new Nuxt(config)
// Build in development
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
// body-parser
app.use(bodyParser())
// mongodb
// session
app.keys = ['some session']
const CONFIG = {
key: 'SESSION', /** (string) cookie key (default is koa:sess) */
/** (number || 'session') maxAge in ms (default is 1 days) */
/** 'session' will result in a cookie that expires when session/browser is closed */
/** Warning: If a session cookie is stolen, this cookie will never expire */
maxAge: 86400000,
overwrite: true, /** (boolean) can overwrite or not (default true) */
httpOnly: true, /** (boolean) httpOnly or not (default true) */
signed: true, /** (boolean) signed or not (default true) */
rolling: false /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. default is false **/
}
app.use(session(CONFIG, app))
// routes
app.use(async (ctx, next) => {
await next()
ctx.status = 200 // koa defaults to 404 when it sees that status is unset
return new Promise((resolve, reject) => {
ctx.res.on('close', resolve)
ctx.res.on('finish', resolve)
nuxt.render(ctx.req, ctx.res, promise => {
// nuxt.render passes a rejected promise into callback on error.
promise.then(resolve).catch(reject)
})
})
})
app.listen(port, host)
console.log('Server listening on ' + host + ':' + port) // eslint-disable-line no-console
}
start()
复制代码
对于 koa-session 的用法,能够参考:从koa-session中间件学习cookie与session
// 登陆
router.post('/api/login', async (ctx, next) => {
const { username, password } = ctx.request.body
let user,
match
try {
user = await Admin.findOne({ user: username }).exec()
if (user) {
match = await user.comparePassword(password, user.password)
}
} catch (e) {
throw new Error(e)
}
if (match) {
ctx.session.user = {
_id: user._id,
username: user.user,
nickname: user.nickname,
role: user.role
}
console.log(ctx.session)
return (ctx.body = {
success: true,
data: {
username: user.user,
nickname: user.nickname
}
})
}
return (ctx.body = {
success: false,
err: '密码错误'
})
})
复制代码
写到这里,整个功能流程基本完毕了,也很是的顺畅,可是对我来讲一路顺风的代码是不存在的。
nuxtServerInit ({ commit }, { req, res }) {
if (req.session && req.session.user) { // res.session is not defined
const { username, password } = req.session.user
const user = {
username,
password
}
commit('SET_USER', user)
}
}
复制代码
在 nuxtServerInit 获取不到有关 session 的任何信息,然而其余的 api 都可获取到 session ,当时因为苦苦找不到缘由,一度怀疑栗子有问题。。
最终的问题仍是由于本身的粗心,忽视了一些细节,在官网给出的栗子中:
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' })
})
复制代码
它将 session 保存在了 req.session , 因此在 nuxtServerInit session也确实存在于 req.session ,而我使用的 Koa2 和 Koa-session ,Koa-session 将 cookie 解析到了 ctx.session , 它并不存在于 req.session 。
因此在将 nuxt.render 注入的时候,将 session 添加进 request 中
app.use(async (ctx, next) => {
await next()
ctx.status = 200 // koa defaults to 404 when it sees that status is unset
ctx.req.session = ctx.session
return new Promise((resolve, reject) => {
ctx.res.on('close', resolve)
ctx.res.on('finish', resolve)
nuxt.render(ctx.req, ctx.res, promise => {
// nuxt.render passes a rejected promise into callback on error.
promise.then(resolve).catch(reject)
})
})
})
复制代码
大功告成!