vue+koa2实现session、token登陆状态验证的示例
Session登陆与Token登陆的区别
1、Session登陆是在服务器端生成用户相关session数据,发给客户端session_id存放到cookie中,这样在客户端请求时带上session_id就可以验证服务器端是否存在session数据,以此完成用户认证。这种认证方式,可以更好的在服务端对会话进行控制,安全性比较高(session_id随机),但是服务端需要存储session数据(如内存或数据库),这样无疑增加维护成本和减弱可扩展性(多台服务器)。CSRF攻击一般基于cookie。另外,如果是原生app使用这种服务接口,因为没有浏览器cookie功能,所以接入会相对麻烦。
2、基于token的用户认证是一种服务端无状态的认证方式,服务端不用存放token数据。用户验证后,服务端生成一个token(hash或encrypt)发给客户端,客户端可以放到cookie或localStorage中,每次请求时在Header中带上token,服务端收到token,通过验证后即可确认用户身份。这种方式相对cookie的认证方式就简单一些,服务端不用存储认证数据,易维护扩展性强,token存在localStorage可避免CSRF,web和app应用都比较简单。不过这种方式在加密或解密的时候会有一些性能开销(好像也不是很大),有些对称加密存在安全隐患(aescbc字节翻转攻击)。
koa+session登陆验证
1、首先要安装koa-sisson包
npminstallkoa-session-S
koa-session实际上是通过cookie来保存信息的。koa-session在服务器上生成一个信息,通过加密后,以cookie的形式发送到用户的浏览器,在用户浏览器上可以看到是一个加密的cookie字段,然后在服务端路由中通过ctx.session.xx来获取xx这个信息。而当每次当用户发送请求时候,就可以获取到这个cookie,koa-sesscion会内部会帮我们解密为最初的存储的信息,于是我们可以通过判断这个cookie是存在来校验用户是否已经登录了。
2、app.js中初始化
constKoa=require('koa') constapp=newKoa() constsession=require('koa-session') constbodyParser=require('koa-bodyparser') constRouter=require('koa-router') constrouter=newRouter() constCONFIG={ key:'koa:sess',/**(string)cookiekey(defaultiskoa:sess)cookie的Name*/ /**(number||'session')maxAgeinms(defaultis1days)*/ /**'session'willresultinacookiethatexpireswhensession/browserisclosed*/ /**Warning:Ifasessioncookieisstolen,thiscookiewillneverexpire*/ maxAge:86400000,/**cookie的过期时间*/ autoCommit:true,/**(boolean)automaticallycommitheaders(defaulttrue)*/ overwrite:true,/**(boolean)canoverwriteornot(defaulttrue)*/ httpOnly:true,/**(boolean)httpOnlyornot(defaulttrue)*/ signed:true,/**(boolean)signedornot(defaulttrue)*/ rolling:false,/**(boolean)Forceasessionidentifiercookietobesetoneveryresponse.TheexpirationisresettotheoriginalmaxAge,resettingtheexpirationcountdown.(defaultisfalse)*/ renew:false,/**(boolean)renewsessionwhensessionisnearlyexpired,sowecanalwayskeepuserloggedin.(defaultisfalse)*/ } app.keys=['loginsecret']//加密密钥 app.use(session(CONFIG,app)); app.use(bodyParser()) app.use(router.routes()).use(router.allowedMethods())
3、登陆路由
router.post('/login',async(ctx)=>{ try{ constdata=ctx.request.body.data const{username,password}=data if(true){ //保存登录状态,这句代码会在浏览器中生成一个以"koa:sess"为Name的cookie ctx.session.userInfo={username:'',userID:''} ctx.body={code:1,message:'登陆成功'} }else{ ctx.body={code:0,message:'账号或密码错误'} } }catch(err){ thrownewError(err) } }) //前端 axios.post('/login',{username:'',password:''}).then(res=>{})
4、校验是否已登陆
router.get('/getSession',async(ctx)=>{ try{ if(ctx.session.userInfo){ ctx.body={code:1,message:'已登陆'} }else{ ctx.body={code:0,message:'未登陆'} //跳转到登录页 //ctx.response.redirect('/login') } }catch(err){ thrownewError(err) } }) //前端 axios.get('/getSession').then(res=>{})
5、退出登陆
router.post('/logout',async(ctx)=>{ try{ //将登录信息清空 ctx.session=null //跳转到登录页或网站首页 ctx.response.redirect('/') }catch(err){ thrownewError(err) } }) //前端 axios.post('/logout').then(res=>{})
koa+token登陆验证
1、安装jsonwebtoken包
npminstalljsonwebtoken-S
2、app.js初始化
constKoa=require('koa') constapp=newKoa() constjwt=require('jsonwebtoken') constbodyParser=require('koa-bodyparser') constRouter=require('koa-router') constrouter=newRouter() consttokenConfig={privateKey:'xxxxxxxxxxxx'}//加密密钥 app.use(bodyParser()) app.use(router.routes()).use(router.allowedMethods())
3、登陆路由
router.post('/login',async(ctx)=>{ try{ constdata=ctx.request.body.data const{username,password}=data if(true){ constuserInfo={username:'',userID:''} consttoken=jwt.sign(userInfo,tokenConfig.privateKey,{expiresIn:'7d'})//签发token,7天有效期 ctx.body={code:1,message:'登陆成功',data:{token:'Bearer'+token}} }else{ ctx.body={code:0,message:'账号或密码错误'} } }catch(err){ thrownewError(err) } })
前端登陆
axios.post('/login',{username:'',password:''}).then(res=>{ if(res.data.code===1){ localStorage.setItem('token',res.data.data.token) //vuex存储userInfo和登陆状态 store.commit('SET_USERINFO',{userInfo:res.data.data.userInfo,status:true}) } })
4、校验是否已登陆
router.get('/getUserInfo',async(ctx)=>{ try{ consttoken=ctx.get('Authorization')//获取请求Header中Authorization值 letuserInfo={} if(token===''){ ctx.body={code:0,message:'未登陆'} }else{ try{ userInfo=jwt.verify(token.split('')[1],tokenConfig.privateKey)//验证token ctx.body={code:1,message:'已登陆',data:{userInfo:userInfo:loginStatus:true}} }catch(err){ //token过期或无效 ctx.body={code:0,message:'未登陆',data:{userInfo:{}:loginStatus:false}}} } } }catch(err){ thrownewError(err) } })
要每次的请求中都带上token信息,要给axios设置请求拦截
//请求拦截,在每次请求中的header中带上token axios.interceptors.request.use(config=>{ lettoken=localStorage.getItem('token') if(token){ config.headers.common.Authorization=token } returnconfig },error=>{ returnPromise.reject(error); })
每次进入页面之前要判断下是否已登陆,是否有权限进入该页面,之前我是在每个页面的created钩子函数中去请求'/getUserInfo'判断是否以登陆,这样做繁琐,并且页面会先呈现一下,然后一闪而过(验证不过的情况下),在路由钩子函数中可全局配置
//路由守卫,在跳转之前执行 router.beforeEach((to,from,next)=>{ lettoken=localStorage.getItem('token') letrequireAuth=to.meta.requireAuth//VueRouter里配置页面是否需要登陆进入 letroot=to.meta.root//VueRouter里配置页面是否需要登陆且管理员权限进入 if(!token){ //vuex清除userInfo和登陆状态 store.commit('SET_USERINFO',{userInfo:{},status:false}) requireAuth?next({path:'/'}):next() }else{ axios.get(API.getUserInfo).then(res=>{ //vuex存储userInfo和登陆状态 store.commit('SET_USERINFO',{userInfo:res.data.userInfo,status:res.data.loginStatus}) if(requireAuth){ if(!res.data.loginStatus||(root&&!res.data.userInfo.root)){ next({path:'/'}) }else{ next() } }else{ next() } }) } }) /**VueRouter { path:'/admin', name:'admin', meta:{ requireAuth:true, root:true }, } */
5、退出登陆
因为服务器端并没有存储用户登陆相关信息,只与前端是否存在token或是否能验证通过有关,所以退出登陆就将token清除即可
methods:{ logout(){ localStorage.removeItem('token') //vuex清除登陆信息 store.commit('SET_USERINFO',{userInfo:{},status:false}) if(this.$route.path!=='/'){ this.$router.push({path:'/'}) } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。