中间件
egg是一个基于koa的框架,中间件是一个函数,在请求与响应之间执行。
上篇博客的登录验证中,获取数据需要校验token,而token校验是写在controller里的。如果代码多起来,很多操作都需要校验token
每个controller都写个校验token的语句就比较繁琐。所以用中间件来完成请求与响应间校验token的功能
创建中间件
middleware目录别写错,写错egg就不认为你写了中间件
点击3次获取数据,后台也会打印3次checktoken。也就是说前台发出请求后,后台要经过中间件才能跳转到控制器
jwt.js
const Controller = require("egg").Controller
class JwtController extends Controller {
async index(){
this.ctx.body = "hi,egg";
}
async doLogin(){//处理用户登录,验证成功就发个token
let user = this.ctx.request.body.user;//前端传过来的user,包含username和password属性
if(user.username === "admin" && user.password === "123456"){
let user_jwt = {userjwt:user.username};//用user.username来签名生成token
let token = this.app.jwt.sign(user_jwt,this.app.config.jwt.secret);
//let token = this.app.jwt.sign({username},this.app.config.jwt.secret);
//这是种简写法,展开来是这样的{username:username},属性username的值是username
this.ctx.body = {
code:20000,
token:token
}//验证成功就给个响应,code和token是自己定义的,像msg那样
}else{//登录失败的响应
this.ctx.body = {
code:40000,
msg:"用户名或密码错误"
}
}
}
async getMessage(){//前端向后台获取信息时校验token
this.ctx.body = "hello jwt";//有中间件就不需要写token校验了
}
}
module.exports = JwtController
checktoken.js
function checktoken(){
return async function(ctx,next){//ctx上下文对象,next路由放行
try{
let token = ctx.request.header.token;//获取请求头里的token属性的值,不能加this
//用户再次请求数据的时候都要带着生成的token给服务器校验
let decode = ctx.app.jwt.verify(token,ctx.app.config.jwt.secret);//ctx.app可以指向应用实例app
console.log(decode)
if(decode.userjwt){
/*如果jwt.js的doLogin中用user生成的token,
那么decode:{ username: 'admin', password: '123456', iat: 1675928007 }
有username和password两个属性,这种情况是decode.username
如果用user_jwt生成的token,由于user_jwt是{userjwt:user.username}定义的
所以它只有一个属性,userjwt,值为user对象的username
decode:{ userjwt: 'admin', iat: 1675928083 }
jwt.js采用user_jwt生成token,所以是decode.userjwt
两种生成token的方式都可以,user容易理解,user_jwt更贴合实际
*/
await next();//放行
}
}catch(e){
ctx.body = {
code:40000,
msg:"用户校验失败"
}
}
}
}
module.exports = checktoken;
router.js
'use strict';//严格模式
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.resources("students","/students",controller.students);
router.get('/jwt', controller.jwt.index);
router.post('/jwtlogin', controller.jwt.doLogin);//处理前端/login提交的表单
router.get('/jwtmessage', app.middleware.checktoken(), controller.jwt.getMessage);
//每次get请求访问/jwtmessage时都会执行中间件checktoken()方法来校验token
};
vue跟上篇博客一样