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 相关文章推荐
jQuery 1.2.x 升? 1.3.x 注意事项
May 06 Javascript
深入理解Javascript作用域与变量提升
Dec 09 Javascript
extJS中常用的4种Ajax异步提交方式
Mar 07 Javascript
Node.js和PHP根据ip获取地理位置的方法
Mar 14 Javascript
node.js应用后台守护进程管理器Forever安装和使用实例
Jun 01 Javascript
javascript闭包(Closure)用法实例简析
Nov 30 Javascript
javascript判断回文数详解及实现代码
Feb 03 Javascript
Jquery+Ajax+xml实现中国地区选择三级联动菜单效果(推荐)
Jun 09 jQuery
超级简易的JS计算器实例讲解(实现加减乘除)
Aug 08 Javascript
浅谈js基础数据类型和引用类型,深浅拷贝问题,以及内存分配问题
Sep 02 Javascript
angular6的table组件开发的实现示例
Dec 26 Javascript
vue.js实现双击放大预览功能
Jun 23 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
ThinkPHP惯例配置文件详解
2014/07/14 PHP
WordPress中获取页面链接和标题的相关PHP函数用法解析
2015/12/17 PHP
CI分页类首页、尾页不显示的解决方法
2016/03/28 PHP
Laravel5.1 框架路由基础详解
2020/01/04 PHP
自己开发Dojo的建议框架
2008/09/24 Javascript
页面加载完成后再执行JS的jquery写法以及区别说明
2014/02/22 Javascript
打造个性化的功能强大的Jquery虚拟键盘(VirtualKeyboard)
2014/10/11 Javascript
js实现从中间开始往上下展开网页窗口的方法
2015/03/02 Javascript
JavaScript获取伪元素(Pseudo-Element)属性的方法技巧
2015/03/13 Javascript
jquery使用animate方法实现控制元素移动
2015/03/27 Javascript
不依赖Flash和任何JS库实现文本复制与剪切附源码下载
2015/10/09 Javascript
基于jQuery实现拖拽图标到回收站并删除功能
2015/11/25 Javascript
AngularJS 2.0新特性有哪些
2016/02/18 Javascript
浅析BootStrap模态框的使用(经典)
2016/04/29 Javascript
最简单的tab切换实例代码
2016/05/13 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
2018/01/08 Javascript
vue使用监听实现全选反选功能
2018/07/06 Javascript
vscode 配置vue+vetur+eslint+prettier自动格式化功能
2020/03/23 Javascript
vue+iview实现分页及查询功能
2020/11/17 Vue.js
[43:57]LGD vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python strip lstrip rstrip使用方法
2008/09/06 Python
Python生成验证码实例
2014/08/21 Python
Python爬取当当、京东、亚马逊图书信息代码实例
2017/12/09 Python
Python实现识别手写数字 Python图片读入与处理
2020/03/23 Python
示例详解Python3 or Python2 两者之间的差异
2018/08/23 Python
python如何将图片转换素描画
2020/09/08 Python
使用Django的JsonResponse返回数据的实现
2021/01/15 Python
css3实现椭圆轨迹旋转的示例代码
2018/10/29 HTML / CSS
美国室内和室外装饰花盆购物网站:ePlanters
2019/03/22 全球购物
澳大利亚实惠时尚女装商店:Katies
2019/06/16 全球购物
俞敏洪北大演讲稿
2014/05/22 职场文书
弘扬焦裕禄精神走群众路线思想汇报
2014/09/12 职场文书
卡特教练观后感
2015/06/08 职场文书
交通安全教育主题班会
2015/08/12 职场文书
会计入职心得体会
2016/01/22 职场文书
详解运行Python的神器Jupyter Notebook
2021/06/03 Python