koa如何使用koa-jwt和jsonwebtoken进行路由认证!!本文使用nuxt.js和koa2作为开发环境。前端存储token的方式是cookie相关的知识。关于jwt的知识可以参考下面这篇文章JSONWebToken-在web应用之间安全传输信息。先安装npm安装我们需要的模块npminstallkoa-jwtjsonwebtokencookieparser注意:koa-jwt使用jsonwebtoken来发布和验证token对。cookieparser模块用于解析cookie,粘贴一个以koa为后台初始索引的nuxt应用框架。js文件constKoa=require("koa");constconsola=require("consola");const{Nuxt,Builder}=require("nuxt");constapp=newKoa();//导入并设置Nuxt.jsoptionsconstconfig=require("../nuxt.config.js");config.dev=app.env!=="production";asyncfunctionstart(){//实例化nuxt.jsconstnuxt=newNuxt(配置);const{host=process.env.HOST||"127.0.0.1",port=process.env.PORT||3000}=nuxt.options.server;//在开发中构建if(config.dev){constbuilder=newBuilder(nuxt);等待builder.build();}else{awaitnuxt.ready();}app.use((ctx,next)=>{ctx.status=200;ctx.respond=false;//绕过Koa内置的响应处理ctx.req.ctx=ctx;//这在以后可能会有用,例如在nuxtServerInit中或使用nuxt-stashnuxt.render(ctx.req,ctx.res);});app.listen(端口,主机);consola.ready({message:`Serverlisteningonhttp://${host}:${port}`,badge:true});}start();使用后端(koa)代码:我们在index.js中引入koa-jwt并使用它constjwt=require("koa-jwt");constSECRET="Publicsecret";app.use(jwt({secret:SECRET}).unless({path:\[/^\\/api\\/login/,/^\\/api\\/register/\]}));注:unless是jwt的一个方法,排除对应的网址认证。我们排除登录和注销路由身份验证。SECRET是后台保存的key,让jsonwebtoken生成一个token字符串。在你的接口文件中引入jsonwebtokenconstjsonwebtoken=require("jsonwebtoken");在/api/login登录界面,如果登录验证成功,则生成token发送给前端,并在cookie中设置值if(result){lettoken=jsonwebtoken.sign(payload,SECRET,{expiresIn:"1h"});ctx.cookies.set("auth",JSON.stringify(token),{maxAge:60000*60,覆盖:真});ctx.body={token:token,user:{}}}注意:payload是payload的意思,如果你看了上面关于jsonwebtoken的文章,我想你就明白了~SECRET就是我们在index.js文件中的key字符串,expiresIn是token的有效时间,字符串的形式,可以放1h,或者一个数字(毫秒),这里随便提一下,如果我们的cookies的httponly选项为true(默认为true)这是防止XSS(能防止到什么程度)就不细说了。这时候我们的index.js文件就变成了这样(api接口文件的代码我就不贴了):constKoa=require("koa");constconsola=require("consola");const{Nuxt,Builder}=require("nuxt");constbodyParser=require("koa-bodyparser");constjwt=require("koa-jwt");//导入登录接口文件constuser=require("./api/user");constSECRET="Publicsecret";constapp=newKoa();//导入并设置Nuxt.js选项constconfig=require("../nuxt.config.js");config.dev=app.env!=="production";asyncfunctionstart(){//实例化nuxt.jsconstnuxt=newNuxt(config);const{host=process.env.HOST||"127.0.0.1",port=process.env.PORT||3000}=nuxt.options.server;//在开发中构建if(config.dev){constbuilder=newBuilder(nuxt);等待builder.build();}else{awaitnuxt.ready();}app.use(jwt({secret:SECRET}).unless({path:\[/^\\/api\\/login/,/^\\/api\\/register/\]}));//使用接口文件app.use(user.routes()).use(user.allowedMethods());app.use((ctx,next)=>{ctx.status=200;ctx.respond=false;//绕过Koa的内置响应处理ctx.req.ctx=ctx;//这以后可能会有用,例如,在nuxtServerInit中或使用nuxt-stashnuxt.render(ctx.req,ctx.res);});app.listen(端口,主机);consola.ready({message:`Serverlisteningonhttp://${host}:${port}`,badge:true});}start();现在我们已经完成了后台的鉴权逻辑,只要有请求,除了/api/login和/api/注册的url都会先通过jwt进行鉴权前端代码:前端处理逻辑是将登录成功后返回的结果中的用户信息保存到store中,然后在axios中添加一个请求拦截器。在header中添加authorization字段,字段内容为“Bearer”+token,Bearer和token之间有空格,添加错误拦截器,jsonwebtoken在验证顺序中卡错了会报错,对应的代码是401这里直接贴代码,axios.js文件就不细说了exportdefaultfunction(app){letaxios=app.$axios;axios.onRequest(config=>{if(app.store.state.authUser){config.headers.authorization="Bearer"+app.store.state.authUser.token;}});axios.onError(error=>{constcode=parseInt(error.response&&error.response.status);if(code===401){//错误处理逻辑}});}store的index.js文件constcookieparser=进程.服务器?require("cookieparser"):undefined;exportconststate=()=>({authUser:null});exportconstmutations={SET_USER(state,user){state.authUser=user;}};exportconstactions={//nuxtServerInit在服务器渲染每个页面之前由Nuxt.js调用nuxtServerInit({commit},{req}){letauth=null;if(req.headers.cookie){constparsed=cookieparser.解析(req.headers.cookie);auth=newBuffer(parsed.authUser.split(".")[1],"base64").toString();尝试{auth=JSON.parse(auth);auth.token=parsed.authUser;//console.log(auth);提交(“SET_USER”,授权);}catch(err){//没有找到有效的cookieconsole.log(err);}}},asynclogin({commit},{username,password}){try{const{data}=awaitthis.$axios.post("/api/login",{name:用户名,password:密码});如果(数据。结果){提交(“SET_USER”,数据);}}catch(error){if(error.response&&error.response.status===401){thrownewError("Badcredentials");}抛出错误;}},};注意:cookieparser模块就是用来解析cookie到这一步的,我们的路由鉴权已经完成了。打完撒花??扩容(还有问题)路由认证没问题,但是如果我全站这么多链接,我不能只有/api/login和/api/logout不需要认证,其他的都要加上。我是否将它们添加到除非?也可以,就是有点麻烦。token过期了怎么办?如果我在后台编辑东西,权限突然过期,那不是很尴尬。所以只要在限定时间内有操作后台,我们就需要更新token。我们修改后台koa中间件,直接贴index.js代码=require("koa-bodyparser");constjsonwebtoken=require("jsonwebtoken");//引入登录接口文件constuser=require("./api/user");constSECRET="Publicsecret";constapp=newKoa();//导入并设置Nuxt.js选项constconfig=require("../nuxt.config.js");config.dev=app.env!=="production";asyncfunctionstart(){//实例化nuxt.jsconstnuxt=newNuxt(config);const{host=process.env.HOST||"127.0.0.1",port=process.env.PORT||3000}=nuxt.options.server;//在开发中构建if(config.dev){constbuilder=newBuilder(nuxt);等待builder.build();}else{awaitnuxt.ready();}//修改在这里app.use((ctx,next)=>{if(ctx.url.match(/^\/api\/login/)||ctx.url.match(/^\/api\/登记/)){返回下一个();}if(ctx.url.match(/^\/api/)){//路由判断url是否以/api开头,如果是则进行认证,否则直接输入内容letauthorization=ctx.headers.authorization,令牌;如果(ctx.headers){如果(!授权){ctx.status=401;return(ctx.body="错误权限");}token=authorization.split("")[1];try{letdecoded=jsonwebtoken.verify(token,SECRET),refresh;//这里写refreshtoken逻辑,refresh是判断是否到了refreshtoken时间的结果if(refresh){//在刷新时间范围内请求refreshtokentry{letnewToken=jsonwebtoken.sign(user,SECRET,{expiresIn:"1h"});ctx.cookies.set("authUser",JSON.stringify(newToken),{maxAge:60000*60,overwrite:true});}catch(err){console.log(err);}}}catch(err){ctx.status=401;return(ctx.body="错误权限");}}返回下一个();}else{ctx.status=200;ctx.respond=false;//绕过Koa内置的响应处理ctx.req.ctx=ctx;//这在以后可能会有用,例如在nuxtServerInit中或使用nuxt-stashnuxt.render(ctx.req,ctx.res);}});app.use(user.routes()).use(user.allowedMethods());app.listen(端口,主机);consola.ready({message:`Serverlisteningonhttp://${host}:${port}`,badge:true});}start();现在终于结束了,我们做到了,只要请求除了/api/login和/api/register,任何以/api开头的url都会执行鉴权,token会不断更新,不怕它会expireifyouuse过期前1小时不操作后台,token过期。token是否需要刷新由当前时间是否超过token发行时间加一小时之和来判断,即currentTime>refreshInterval+iat;如果结果为真,token将刷新Card。最后,如有错误,请指出,谢谢??
