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 相关文章推荐
Javascript 面向对象 继承
May 13 Javascript
关于jQuery object and DOM element
Apr 15 Javascript
基于OO的动画附加插件,可以实现弹跳、渐隐等动画效果 分享
Jun 24 Javascript
Javascript刷新窗口方法小结
Oct 21 Javascript
jQuery时间日期三级联动(推荐)
Nov 27 Javascript
JavaScript获取中英文混合字符串长度的方法示例
Feb 04 Javascript
Vue插件打包与发布的方法示例
Aug 20 Javascript
小程序组件之自定义顶部导航实例
Jun 12 Javascript
JS防抖和节流实例解析
Sep 24 Javascript
谈谈node.js中的模块系统
Sep 01 Javascript
探索node之事件循环的实现
Oct 30 Javascript
浅谈node.js中间件有哪些类型
Apr 29 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 ? EasyUI DataGrid 资料存的方式介绍
2012/11/07 PHP
php excel reader读取excel内容存入数据库实现代码
2012/12/06 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
2015/07/28 PHP
ThinkPHP5与单元测试PHPUnit使用详解
2020/02/23 PHP
简单JS代码压缩器
2006/10/12 Javascript
jQuery 常见学习网站与参考书
2009/11/09 Javascript
js设置组合快捷键/tabindex功能的方法
2013/11/21 Javascript
前台js调用后台方法示例
2013/12/02 Javascript
ajax+jQuery实现级联显示地址的方法
2015/05/06 Javascript
JavaScript对象数组排序函数及六个用法
2015/12/23 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
2017/01/11 Javascript
很棒的一组js图片轮播特效
2017/01/12 Javascript
mint-ui在vue中的使用示例
2018/04/05 Javascript
在 Vue 项目中引入 tinymce 富文本编辑器的完整代码
2018/05/04 Javascript
JavaScript捕捉事件和阻止冒泡事件实例分析
2018/08/03 Javascript
Next.js项目实战踩坑指南(笔记)
2018/11/29 Javascript
[01:51]历届DOTA2国际邀请赛举办地回顾 TI9落地上海
2018/08/26 DOTA
Python的动态重新封装的教程
2015/04/11 Python
基于python yield机制的异步操作同步化编程模型
2016/03/18 Python
Mac中升级Python2.7到Python3.5步骤详解
2017/04/27 Python
使用django-crontab实现定时任务的示例
2018/02/26 Python
解决Pyinstaller打包软件失败的一个坑
2021/03/04 Python
移动Web—CSS为Retina屏幕替换更高质量的图片
2012/12/24 HTML / CSS
One.com挪威:北欧成长最快的网络托管公司
2016/11/19 全球购物
TripAdvisor日本:全球领先的旅游网站
2019/02/14 全球购物
西班牙购买隐形眼镜、眼镜和太阳镜网站:Lentiamo.es
2020/06/11 全球购物
Myprotein中国网站:欧洲畅销运动营养品牌
2021/02/11 全球购物
转预备党员政审材料
2014/02/06 职场文书
应聘医药销售自荐书范文
2014/02/08 职场文书
高一新生军训感言
2014/03/02 职场文书
学术研讨会欢迎词
2015/01/26 职场文书
检讨书模板
2015/01/29 职场文书
小学生作文之《压岁钱的烦恼》
2019/09/27 职场文书
深入理解 Golang 的字符串
2022/05/04 Golang
Nginx 常用配置
2022/05/15 Servers
win10滚动条自动往上跑怎么办?win10滚动条自动往上跑的解决方法
2022/08/05 数码科技