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 alert消息换行的方法
Aug 07 Javascript
JS格式化数字金额用逗号隔开保留两位小数
Oct 18 Javascript
禁用JavaScript控制台调试的方法
Mar 07 Javascript
JavaScript中的console.assert()函数介绍
Dec 29 Javascript
jQuery实现指定区域外单击关闭指定层的方法【经典】
Jun 22 Javascript
input输入框内容实时监测(附代码)
Aug 15 Javascript
前端跨域的几种解决方式总结(推荐)
Aug 16 Javascript
[js高手之路]从原型链开始图解继承到组合继承的产生详解
Aug 28 Javascript
详细分析JS函数去抖和节流
Dec 05 Javascript
zTree树形菜单交互选项卡效果的实现方法
Dec 25 Javascript
使用validate.js实现表单数据提交前的验证方法
Sep 04 Javascript
详解vue 不同环境配置不同的打包命令
Apr 07 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
PHPMailer邮件发送的实现代码
2013/05/04 PHP
Linux编译升级php的详细方法
2013/11/04 PHP
php版微信自动登录并获取昵称的方法
2016/09/23 PHP
PHP序列化和反序列化深度剖析实例讲解
2020/12/29 PHP
JavaScript 事件属性绑定带参数的函数
2009/03/13 Javascript
JS仿flash上传头像效果实现代码
2011/07/18 Javascript
JavaScript的strict模式与with关键字介绍
2014/02/08 Javascript
Node.js插件的正确编写方式
2014/08/03 Javascript
javascript日期格式化方法汇总
2015/10/04 Javascript
JS模仿手机端九宫格登录功能实现代码
2016/04/28 Javascript
简单实现Vue的observer和watcher
2016/12/21 Javascript
js使用Replace结合正则替换重复出现的字符串功能示例
2016/12/27 Javascript
JavaScript实现简单的四则运算计算器完整实例
2017/04/28 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
jQuery滑动到底部加载下一页数据的实例代码
2017/05/22 jQuery
node实现基于token的身份验证
2018/04/09 Javascript
用Electron写个带界面的nodejs爬虫的实现方法
2019/01/29 NodeJs
vue实现购物车的小练习
2020/12/21 Vue.js
[01:02]DOTA2辉夜杯决赛日 CDEC.Y对阵VG赛前花絮
2015/12/27 DOTA
Python的Flask框架中集成CKeditor富文本编辑器的教程
2016/06/13 Python
利用python获取某年中每个月的第一天和最后一天
2016/12/15 Python
Python爬虫:通过关键字爬取百度图片
2017/02/17 Python
python+selenium+Chrome options参数的使用
2020/03/18 Python
django实现HttpResponse返回json数据为中文
2020/03/27 Python
pytorch 中的重要模块化接口nn.Module的使用
2020/04/02 Python
利用纯CSS3实现文字向右循环闪过效果实例(可用于移动端)
2017/06/15 HTML / CSS
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
巴西最大的家具及装饰用品店:Mobly
2017/10/11 全球购物
软件测试企业面试试卷
2016/07/13 面试题
通用求职信范文模板分享
2013/12/27 职场文书
西北政法大学自主招生自荐信
2014/01/29 职场文书
绿色城市实施方案
2014/03/19 职场文书
会议接待欢迎词范文
2015/01/26 职场文书
JavaScript 语句之常用 for 循环详解
2021/03/29 Javascript
python3.7.2 tkinter entry框限定输入数字的操作
2021/05/22 Python
Python中OpenCV实现简单车牌字符切割
2021/06/11 Python