nuxt框架中路由鉴权之Koa和Session的用法
引子
博客的后台管理页面需要有登录系统,所以考虑做一下路由鉴权,实现方式也是Nuxt官网给出栗子来改写,顺便也将前后端路由给统一了。
路由拦截
前端方面主要通过利用Nuxt的中间件来做路由拦截,这里也是需要Vuex状态树来做。
middleware
middleware/auth.js
exportdefaultfunction({store,redirect}){ if(!store.state.user){ returnredirect('/login') } }
通过对状态树上的用户信息是否存在来鉴权,来对页面进行重定向
layouts/admin.vue
exportdefault{ middleware:'auth', components:{ AdminAside } }
在后台管理系统的页面布局上添加中间件
nuxtServerInit
在NuxtJs的渲染流程中,当请求打入时,最先调用的即是nuxtServerInit方法,可以通过这个方法预先将服务器的数据保存。
我们可以利用该方法来接收存储用户信息的Session信息。
nuxtServerInit({commit},{req,res}){ if(req.session&&req.session.user){ const{username,password}=req.session.user constuser={ username, password } commit('SET_USER',user) } },
当应用完毕时,一些我们从服务器获取到的数据就会被填充到这个状态树(store)上。
按照NuxtJs官网给出的栗子来看,到这里基本算把页面中路由鉴权部分写完了,接下来是对服务器端该部分代码的写作
使用Koa和koa-session
Koa和koa-session
后端代码我采用是Koa框架,以及koa-session来对Session做处理。
在新建nuxt项目的时候直接选用Koa框架即可
vueinitnuxt/koa
相关依赖
npminstallkoa-session
在server.js中改写
importKoafrom'koa' import{Nuxt,Builder}from'nuxt' //afterend importsessionfrom'koa-session' asyncfunctionstart(){ constapp=newKoa() consthost=process.env.HOST||'127.0.0.1' constport=process.env.PORT||7998 //ImportandSetNuxt.jsoptions letconfig=require('../nuxt.config.js') config.dev=!(app.env==='production') //Instantiatenuxt.js constnuxt=newNuxt(config) //Buildindevelopment if(config.dev){ constbuilder=newBuilder(nuxt) awaitbuilder.build() } //body-parser app.use(bodyParser()) //mongodb //session app.keys=['somesession'] constCONFIG={ key:'SESSION',/**(string)cookiekey(defaultiskoa:sess)*/ /**(number||'session')maxAgeinms(defaultis1days)*/ /**'session'willresultinacookiethatexpireswhensession/browserisclosed*/ /**Warning:Ifasessioncookieisstolen,thiscookiewillneverexpire*/ maxAge:86400000, overwrite:true,/**(boolean)canoverwriteornot(defaulttrue)*/ httpOnly:true,/**(boolean)httpOnlyornot(defaulttrue)*/ signed:true,/**(boolean)signedornot(defaulttrue)*/ rolling:false/**(boolean)Forceasessionidentifiercookietobesetoneveryresponse.TheexpirationisresettotheoriginalmaxAge,resettingtheexpirationcountdown.defaultisfalse**/ } app.use(session(CONFIG,app)) //routes app.use(async(ctx,next)=>{ awaitnext() ctx.status=200//koadefaultsto404whenitseesthatstatusisunset returnnewPromise((resolve,reject)=>{ ctx.res.on('close',resolve) ctx.res.on('finish',resolve) nuxt.render(ctx.req,ctx.res,promise=>{ //nuxt.renderpassesarejectedpromiseintocallbackonerror. promise.then(resolve).catch(reject) }) }) }) app.listen(port,host) console.log('Serverlisteningon'+host+':'+port)//eslint-disable-lineno-console } start()
对于koa-session的用法,可以参考:从koa-session中间件学习cookie与session
登录路由
//登录 router.post('/api/login',async(ctx,next)=>{ const{username,password}=ctx.request.body letuser, match try{ user=awaitAdmin.findOne({user:username}).exec() if(user){ match=awaituser.comparePassword(password,user.password) } }catch(e){ thrownewError(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:'密码错误' }) })
写到这里,整个功能流程基本完毕了,也非常的顺畅,但是对我来说一帆风顺的代码是不存在的。
sessionisnotdefined
问题
nuxtServerInit({commit},{req,res}){ if(req.session&&req.session.user){//res.sessionisnotdefined const{username,password}=req.session.user constuser={ 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'} returnres.json({username:'demo'}) } res.status(401).json({error:'Badcredentials'}) })
它将session保存在了req.session,所以在nuxtServerInitsession也确实存在于req.session,而我使用的Koa2和Koa-session,Koa-session将cookie解析到了ctx.session,它并不存在于req.session。
解决
所以在将nuxt.render注入的时候,将session添加进request中
app.use(async(ctx,next)=>{ awaitnext() ctx.status=200//koadefaultsto404whenitseesthatstatusisunset ctx.req.session=ctx.session returnnewPromise((resolve,reject)=>{ ctx.res.on('close',resolve) ctx.res.on('finish',resolve) nuxt.render(ctx.req,ctx.res,promise=>{ //nuxt.renderpassesarejectedpromiseintocallbackonerror. promise.then(resolve).catch(reject) }) }) })
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。