引子
博客的后台管理页面需要有登录系统, 所以考虑做一下路由鉴权, 实现方式也是 Nuxt 官网给出栗子来改写, 顺便也将前后端路由给统一了.
路由拦截
前端方面主要通过利用 Nuxt 的中间件来做路由拦截, 这里也是需要 vuex 状态树来做.
- middleware
- middleware/auth.js
- export default function ({store, redirect}) {
- if (!store.state.user) {
- return redirect('/login')
- }
- }
通过对状态树上的用户信息是否存在来鉴权, 来对页面进行重定向
- layouts/admin.vue
- export default {
- middleware: 'auth',
- components: {
- AdminAside
- }
- }
在后台管理系统的页面布局上添加 中间件
nuxtServerInit
在 NuxtJs 的渲染流程中, 当请求打入时, 最先调用的即是 nuxtServerInit 方法, 可以通过这个方法预先将服务器的数据保存.
我们可以利用该方法来接收存储用户信息的 Session 信息.
- 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 官网给出的栗子来看, 到这里基本算把页面中路由鉴权部分写完了, 接下来是对服务器端该部分代码的写作
使用 Koa 和 koa-session
Koa 和 koa-session
后端代码我采用是 Koa 框架, 以及 koa-session 来对 Session 做处理.
在新建 nuxt 项目的时候直接选用 Koa 框架即可
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 https://github.com/zyl1314/blog/issues/3
登录路由
- // 登录
- 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: '密码错误'
- })
- })
写到这里, 整个功能流程基本完毕了, 也非常的顺畅, 但是对我来说一帆风顺的代码是不存在的.
session is not defined
问题
- 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)
- })
- })
- })
来源: http://www.jb51.net/article/139804.htm