JSON Web Token
(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于做为JSON
对象在各方之间安全地传输信息。该信息能够被验证和信任,由于它是数字签名的。javascript
本文只讲Koa2 + jwt
的使用,不了解JWT
的话请到这里)进行了解。前端
要使用koa2+jwt
须要先有个koa
的空环境,搭环境比较麻烦,我直接使用koa起手式,这是我使用koa+typescript
搭建的空环境,若是你也常常用koa
写写小demo
,能够点个star,方便~java
koa-jwt
主要做用是控制哪些路由须要jwt验证,哪些接口不须要验证:ios
import * as koaJwt from 'koa-jwt'; //路由权限控制 除了path里的路径不须要验证token 其余都要 app.use( koaJwt({ secret: secret.sign }).unless({ path: [/^\/login/, /^\/register/] }) );
上面代码中,除了登陆、注册接口不须要jwt验证,其余请求都须要。git
执行npm install jsonwebtoken
安装jsonwebtoken
相关代码:github
import * as jwt from 'jsonwebtoken'; const secret = 'my_app_secret'; const payload = {user_name:'Jack', id:3, email: '1234@gmail.com'}; const token = jwt.sign(payload, secret, { expiresIn: '1h' });
上面代码中经过jwt.sign
来生成一个token,
参数意义:web
import * as crypto from 'crypto'; import * as jwt from 'jsonwebtoken'; async login(ctx){ //从数据库中查找对应用户 const user = await userRespository.findOne({ where: { name: user.name } }); //密码加密 const psdMd5 = crypto .createHash('md5') .update(user.password) .digest('hex'); //比较密码的md5值是否一致 若一致则生成token并返回给前端 if (user.password === psdMd5) { //生成token token = jwt.sign(user, secret, { expiresIn: '1h' }); //响应到前端 ctx.body = { token } } }
前端经过登陆拿到返回过来的token
,能够将它存在localStorage
里,而后再之后的请求中把token
放在请求头的Authorization
里带给服务端。
这里以axios
请求为例,在发送请求时,经过请求拦截器把token
塞到header
里:typescript
//请求拦截器 axios.interceptors.request.use(function(config) { //从localStorage里取出token const token = localStorage.getItem('tokenName'); //把token塞入Authorization里 config.headers.Authorization = `Bearer ${token}`; return config; }, function(error) { // Do something with request error return Promise.reject(error); } );
前端发送请求携带token,后端须要判断如下几点:数据库
关于上面两点,须要在后端写一个中间件来完成:npm
app.use((ctx, next) => { if (ctx.header && ctx.header.authorization) { const parts = ctx.header.authorization.split(' '); if (parts.length === 2) { //取出token const scheme = parts[0]; const token = parts[1]; if (/^Bearer$/i.test(scheme)) { try { //jwt.verify方法验证token是否有效 jwt.verify(token, secret.sign, { complete: true }); } catch (error) { //token过时 生成新的token const newToken = getToken(user); //将新token放入Authorization中返回给前端 ctx.res.setHeader('Authorization', newToken); } } } } return next().catch(err => { if (err.status === 401) { ctx.status = 401; ctx.body = 'Protected resource, use Authorization header to get access\n'; } else { throw err; }}); });
上面中间件是须要验证token时都须要走这里,能够理解为拦截器,在这个拦截器中处理判断token是否正确及是否过时,并做出相应处理。
后端更换新token后,前端也须要获取新token 这样请求才不会报错。
因为后端更新的token是在响应头里,因此前端须要在响应拦截器中获取新token。
依然以axios
为例:
//响应拦截器 axios.interceptors.response.use(function(response) { //获取更新的token const { authorization } = response.headers; //若是token存在则存在localStorage authorization && localStorage.setItem('tokenName', authorization); return response; }, function(error) { if (error.response) { const { status } = error.response; //若是401或405则到登陆页 if (status == 401 || status == 405) { history.push('/login'); } } return Promise.reject(error); } );