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 相关文章推荐
extjs 学习笔记(一) 一些基础知识
Oct 13 Javascript
基于jquery封装的一个js分页
Nov 15 Javascript
JavaScript 学习笔记之基础中的基础
Jan 13 Javascript
js查看一个函数的执行时间实例代码
Sep 12 Javascript
全面解析Node.js 8 重要功能和修复
Jun 02 Javascript
vue实现的上传图片到数据库并显示到页面功能示例
Mar 17 Javascript
vue 2.8.2版本配置刚进入时候的默认页面方法
Sep 21 Javascript
Echarts地图添加引导线效果(labelLine)
Sep 30 Javascript
在vue-cli中引入lodash.js并使用详解
Nov 13 Javascript
Node.js控制台彩色输出的方法与原理实例详解
Dec 01 Javascript
vue中的使用token的方法示例
Mar 10 Javascript
vant组件中 dialog的确认按钮的回调事件操作
Nov 04 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
DOTA2 探索永无止境 玩家自创强悍插眼攻略
2020/04/20 DOTA
适用于php-5.2 的 php.ini 中文版[金步国翻译]
2011/04/17 PHP
php计算两个日期相差天数的方法
2015/03/14 PHP
php rsa 加密,解密,签名,验签详解
2016/12/06 PHP
php实现xml转换数组的方法示例
2017/02/03 PHP
javascript分页代码实例分享(js分页)
2013/12/13 Javascript
javascript获取web应用根目录的方法
2014/02/12 Javascript
Bootstrap每天必学之按钮(一)
2015/11/24 Javascript
jquery实现二级导航下拉菜单效果
2015/12/18 Javascript
分享JavaScript与Java中MD5使用两个例子
2015/12/23 Javascript
深入理解React中es6创建组件this的方法
2016/08/29 Javascript
详解webpack 多页面/入口支持&公共组件单独打包
2017/06/29 Javascript
AngularJS常见过滤器用法实例总结
2017/07/06 Javascript
jQury Ajax使用Token验证身份实例代码
2017/09/22 Javascript
解决Linux无法正常安装与卸载Node.js的方法
2018/01/19 Javascript
关于HTML5的data-*自定义属性的总结
2018/05/05 Javascript
实例详解vue.js浅度监听和深度监听及watch用法
2018/08/16 Javascript
如何使用CSS3+JQuery实现悬浮墙式菜单
2019/06/18 jQuery
Django中处理出错页面的方法
2015/07/15 Python
十个Python程序员易犯的错误
2015/12/15 Python
Python模块文件结构代码详解
2018/02/03 Python
python实现列表中由数值查到索引的方法
2018/06/27 Python
python格式化输出保留2位小数的实现方法
2019/07/02 Python
python列表返回重复数据的下标
2020/02/10 Python
Python3爬虫中关于Ajax分析方法的总结
2020/07/10 Python
Python 绘制可视化折线图
2020/07/22 Python
HTML5实现表单自动验证功能实例代码
2017/01/11 HTML / CSS
日本7net购物网:书籍、漫画、杂志、DVD、游戏邮购
2017/02/17 全球购物
ghd官网:英国ghd直发器品牌
2018/05/04 全球购物
*p++ 自增p 还是p所指向的变量
2016/07/16 面试题
写一个函数返回1+2+3+…+n的值(假定结果不会超过长整型变量的范围)
2014/09/05 面试题
应聘教师自荐信
2013/10/12 职场文书
公司端午节活动方案
2014/02/04 职场文书
保密普查工作实施方案
2014/02/25 职场文书
专项资金申请报告
2015/05/15 职场文书
老生常谈 使用 CSS 实现三角形的技巧(多种方法)
2021/04/13 HTML / CSS