当前位置: 首页 > Web前端 > vue.js

Koa&Mongoose&Vue实现前后端分离--09认证JWT&测试

时间:2023-04-01 01:53:23 vue.js

最后一节回顾嵌套路由页面布局状态管理&持久化工作内容身份认证准备npmi-Scrypto-js//首先切换到/server目录下的npmi-Skoa-jwt//先切换到/server目录下的npmi-Sjsonwebtoken//切换到/server目录下的业务逻辑JWT"."定界符分为三个子串。JWT分为三部分:JWTheader、payload和signature。JWT一经签发,在有效期内保持有效。JWT签名鉴权解码使用的核心步骤这里使用jsonwebtoken对payload进行签名,jsonwebtoken结合koa-jwt进行签名鉴权,最后是签名前的数据ctx.state[]工具库:signature//新文件:/server/config/auth.jsconstAES=require("crypto-js/aes");constsecretText='jwt.secret.text';constkey='jwt.secret.key'////Encrypt//varciphertext=CryptoJS.AES.encrypt('mymessage','secretkey123').toString();////Decrypt//varbytes=CryptoJS.AES.decrypt(ciphertext,'秘密密钥123)');//varoriginalText=bytes.toString(CryptoJS.enc.Utf8);//console.log(originalText);//'mymessage'module.exports={secret:AES.encrypt(secretText,key).toString(),authKey:'auth'}可以通过ctx.state[]得到payload,即ctx.state.auth.//新建一个文件:server/utils/auth.jsconstjwt=require('jsonwebtoken')const{secret}=require('../config/auth')//定义超时时间:token的有效期constexpiresIn='2h';module.exports={sign:function(payload){//建议加密payload。consttoken=jwt.sign(payload,secret,{expiresIn});返回令牌;},vertify:function(ctx,decodeToken,token){}}工具库:认证//更新文件:server/utils/auth.js...vertify:function(ctx,decodeToken,token){letresult=true;try{jwt.verify(token,secret);结果=假;}catch(e){}返回结果;}...vertify返回true表示token无效或者认证失败;vertify返回false表示令牌仍然有效且成功;解析//更新文件:server/app.js...constkoaJwt=require('koa-jwt');const{secret,authKey}=require('./config/auth');const{vertify}=require('./utils/auth');...app.use(koaJwt({//必须放在route前面,否则,无效secret,key:authKey,//jwt是否撤销isRevoked:vertify}))...JWT鉴权一定要放在路由前面,否则路由逻辑就走完了,再进行鉴权。koa-jwt的帮助有什么用?实现认证逻辑,如果认证失败,则抛出错误。koa-jwt类似于koa-body,它解析payload并将其存储在ctx.state[](ctx.state.auth)中。服务器登录返回令牌//更新文件:...constauth=require('../utils/auth');...asyncfunctionlogin(ctx){...if(user){consttoken=auth.sign({id:user.id,account})ctx.body={code:'200',data:{token,id:user.id,account,alias:user.alias},msg:'登录成功'}}...}Postman测试结果vs代码调试控制台异常处理之前的认证失败,抛出ERROR。可以通过断点查看错误信息,补充异常逻辑。官方建议是通过status来判断是否是鉴权错误//updatefile:server/app.js···//中间件错误处理app.use(function(ctx,next){returnnext().catch((err)=>{console.log(err)if(err.name==='ValidationError'){ctx.body={code:'403',data:null,msg:err.message}}elseif(401==err.status){//认证错误ctx.status=401;//更新HTTP响应码ctx.body={code:'401',data:null,msg:`${err.message}\nPlease先登录`}}else{throwerr;}});});···Postman继续测试白名单登录,需要认证?答案是不。不仅仅是登录,注册及其后续的静态图片访问,都不需要身份验证。//更新文件:server/app.jssecret,key:authKey,//jwt是否被撤销isRevoked:vertify}).unless({//返回true表示忽略认证custom:function(ctx){const{method,path,query}=ctx;if(path==='/'){returntrue;}if(path==='/users'&&query.action){returntrue;}returnfalse;}}));chain调用unless并返回true以忽略身份验证。unless的具体用法和koa-unless是一样的,这里使用的自定义是自定义忽略规则。Postman继续测试成功,完美。Postman测试身份认证但是使用Postman测试其他接口:这是因为请求头Headers中没有添加认证信息Authorization。在登录界面的Tests面板中,根据右侧提示设置全局变量token作为登录返回数据的token。//更新测试面板的内容:pm.test("Yourtestname",function(){varjsonData=pm.response.json();pm.globals.set("token",jsonData.data.token);});在需要认证的测试接口的Authorization面板中,Type选择BearerToken,value选择变量{{token}}。前端请求拦截到目前为止,接口没有问题,但是前端页面请求没有添加Authorization。//更新文件:client/src/views/login/index.vue...asyncfunctiononLogin(){...if(res&&res.code==='200'){const{token,...user}=res.data//添加localStorage.setItem('token',res.data.token)//添加this.$store.commit('putLoginer',user)this.$router.replace('/home')}...}...登录时获取token,保存在本地。//更新文件:client/src/utils/http.js...instance.interceptors.request.use(async(config)=>{consttoken=awaitlocalStorage.getItem('token')token&&(config.headers['Authorization']=`Bearer${token}`)returnconfig},function(error){console.log('------request===========',error)//DosomethingwithrequesterrorreturnPromise.reject(error)})...拦截请求。当令牌存在时,将令牌分配给config.headers['Authorization']。分配以Bearer为前缀,这是规范并且需要这样做。//仅用于测试身份认证,测试完成后,恢复文件。//更新文件:client/src/views/homePage/index.vue......测试结果:前端响应拦截前端认证失败,然后返回登录/页面,清除本地存储和vuex。(注销时,这些都是一样的步骤,之前已经处理过注销逻辑)//更新文件:client/src/utils/http.js...importrouterfrom'@/router'importstorefrom'@/store'...instance.interceptors.response.use(asyncres=>{if(/^20./.test(res.status)){returnres.data}if(/^40./.test(res.status)){router.push('/')awaitlocalStorage.clear()store.commit('resetVuex')return{code:'401',msg:'请重新登录'}}console.log('------response=======',res)returnres},error=>{returnPromise.reject(error)})测试结果如下:返回登录/页面,clearlocalstorage和vuex至于为什么/users接口被调用了两次,因为/home认证了一次,/login被调用了一次。这里改进一下/login的调用,有token就认证成功,可以直接进入首页。(偷懒:最好专门做一个认证接口)//更新文件:client/src/views/login/index.vue...asynccreated(){constres=awaithttp.get('/users')if(res.code==='200'){this.$router.replace('/home')}}...参考文档koa-jwtjsonwebtoken