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中的相等与不等运算
Apr 25 Javascript
open 动态修改img的onclick事件示例代码
Nov 13 Javascript
对于Form表单reset方法的新认识
Mar 05 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
Mar 30 Javascript
javascript实现网站加入收藏功能
Dec 16 Javascript
jQuery实现带水平滑杆的焦点图动画插件
Mar 08 Javascript
JavaScript定时器setTimeout()和setInterval()详解
Aug 18 Javascript
微信小程序获取用户信息并保存登录状态详解
May 10 Javascript
在layui中使用form表单监听ajax异步验证注册的实例
Sep 03 Javascript
Vue extend的基本用法(实例详解)
Dec 09 Javascript
详解ES6 中的Object.assign()的用法实例代码
Jan 11 Javascript
ReactRouter的实现方法
Jan 25 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服务器实现多session并发运行
2006/10/09 PHP
php函数连续调用实例分析
2015/07/30 PHP
网页的分页下标生成代码(PHP后端方法)
2016/02/03 PHP
TP3.2批量上传文件或图片 同名冲突问题的解决方法
2017/08/01 PHP
javascript 按回车键相应按钮提交事件
2009/11/02 Javascript
在网页中使用document.write时遭遇的奇怪问题
2010/08/24 Javascript
js 自制滚动条的小例子
2013/03/16 Javascript
js设置文本框中焦点位置在最后的示例代码(简单实用)
2014/03/04 Javascript
javascript面向对象快速入门实例
2015/01/13 Javascript
Javascript基础教程之数据类型转换
2015/01/18 Javascript
js实现Select下拉框具有输入功能的方法
2015/02/06 Javascript
js判断手机端(Android手机还是iPhone手机)
2015/07/22 Javascript
实例讲解JavaScript中instanceof运算符的用法
2016/06/08 Javascript
关于js原型的面试题讲解
2016/09/25 Javascript
javascript实现简单的可随机变色网页计算器示例
2016/12/30 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
vue组件发布到npm简单步骤
2017/11/30 Javascript
VUE渲染后端返回含有script标签的html字符串示例
2019/10/28 Javascript
three.js欧拉角和四元数的使用方法
2020/07/26 Javascript
在Python的Flask框架中使用日期和时间的教程
2015/04/21 Python
python实现发送邮件功能
2017/07/22 Python
python爬虫_自动获取seebug的poc实例
2017/08/05 Python
怎么使用pipenv管理你的python项目
2018/03/12 Python
Python+OpenCV目标跟踪实现基本的运动检测
2018/07/10 Python
Python递归函数实例讲解
2019/02/27 Python
Python常见数据类型转换操作示例
2019/05/08 Python
PyQt5高级界面控件之QTableWidget的具体使用方法
2020/02/23 Python
python logging模块的使用
2020/09/07 Python
屈臣氏俄罗斯在线商店:Watsons俄罗斯
2020/08/03 全球购物
成教自我鉴定
2013/10/27 职场文书
酒店客房服务员岗位职责
2015/04/09 职场文书
2015小学五年级班主任工作总结
2015/05/21 职场文书
辞职离别感言
2015/08/04 职场文书
详解Python中的进程和线程
2021/06/23 Python
springboot集成springCloud中gateway时启动报错的解决
2021/07/16 Java/Android
Python实现抖音热搜定时爬取功能
2022/03/16 Python