nuxt框架中路由鉴权之Koa和Session的用法


Posted in Javascript onMay 09, 2018

引子

博客的后台管理页面需要有登录系统,所以考虑做一下路由鉴权,实现方式也是 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

登录路由

// 登录
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)
   })
  })
 })

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Stop SQL Server
Jun 21 Javascript
javascript 三种方法实现获得和设置以及移除元素属性
Mar 20 Javascript
什么是MEAN?JavaScript编程中的MEAN是什么意思?
Dec 18 Javascript
js实现类似于add(1)(2)(3)调用方式的方法
Mar 04 Javascript
javascript动态设置样式style实例分析
May 13 Javascript
实例讲解JS中setTimeout()的用法
Jan 28 Javascript
微信小程序  自定义创建详细介绍
Oct 27 Javascript
touch.js 拖动、缩放、旋转 (鼠标手势)功能代码
Feb 04 Javascript
JavaScript中数组Array.sort()排序方法详解
Mar 01 Javascript
浅谈Node模块系统及其模式
Nov 17 Javascript
给localStorage设置一个过期时间的方法分享
Nov 06 Javascript
深入了解js原型模式
May 30 Javascript
jQuery简单实现的HTML页面文本框模糊匹配查询功能完整示例
May 09 #jQuery
JS验证输入的是否是数字及保留几位小数问题
May 09 #Javascript
javaScript强制保留两位小数的输入数校验和小数保留问题
May 09 #Javascript
node puppeteer(headless chrome)实现网站登录
May 09 #Javascript
JS中移除非数字最多保留一位小数
May 09 #Javascript
JS关于刷新页面的相关总结
May 09 #Javascript
Vue引入jquery实现平滑滚动到指定位置
May 09 #jQuery
You might like
php 将字符串按大写字母分隔成字符串数组
2010/04/30 PHP
ThinkPHP关联模型操作实例分析
2012/09/23 PHP
codeigniter教程之上传视频并使用ffmpeg转flv示例
2014/02/13 PHP
PHP使用FFmpeg获取视频播放总时长与码率等信息
2016/09/13 PHP
iOS+PHP注册登录系统 PHP部分(上)
2016/12/26 PHP
Laravel框架使用Seeder实现自动填充数据功能
2018/06/13 PHP
Javascript 解疑
2009/11/11 Javascript
Extjs4实现两个GridPanel之间数据拖拽功能具体方法
2013/11/21 Javascript
JQuery中使用Ajax赋值给全局变量异常的解决方法
2014/01/10 Javascript
父页面显示遮罩层弹出半透明状态的dialog
2014/03/04 Javascript
jQuery修改li下的样式以及li下的img的src的值的方法
2014/11/02 Javascript
Javascript Object 对象学习笔记
2014/12/17 Javascript
修复jQuery tablesorter无法正确排序的bug(加千分位数字后)
2016/03/30 Javascript
JavaScript暂停和继续定时器的实现方法
2016/07/18 Javascript
清除js缓存的多种方法总结
2016/12/09 Javascript
JS实现马赛克图片效果完整示例
2019/04/13 Javascript
vue解决花括号数据绑定不成功的问题
2019/10/30 Javascript
vue 在methods中调用mounted的实现操作
2020/08/07 Javascript
[01:01]2020完美高校联赛(秋)西安落幕
2021/03/11 DOTA
Python中使用PyHook监听鼠标和键盘事件实例
2014/07/18 Python
Python教程之全局变量用法
2016/06/27 Python
Python中循环引用(import)失败的解决方法
2018/04/22 Python
Python父目录、子目录的相互调用方法
2019/02/16 Python
PyTorch搭建一维线性回归模型(二)
2019/05/22 Python
pytorch在fintune时将sequential中的层输出方法,以vgg为例
2019/08/20 Python
python Zmail模块简介与使用示例
2020/12/19 Python
你不知道的5个HTML5新功能
2016/06/28 HTML / CSS
质检员的岗位职责
2013/11/15 职场文书
人力资源作业细则
2014/03/03 职场文书
事假请假条范文
2014/04/11 职场文书
道德之星事迹材料
2014/05/03 职场文书
2014医学院领导干部四风对照检查材料思想汇报
2014/09/16 职场文书
2015年初中元旦晚会活动总结
2014/11/28 职场文书
保证书格式
2015/01/16 职场文书
nginx部署多前端项目的几种方法
2021/05/25 Servers
Python实现批量自动整理文件
2022/03/16 Python