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)
})
})
})
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。