由于面试了前端,但是我简历上写着我会后端所以被问到了token验证这个问题,但是我自己的项目是没有用到的,他问了我jwt的组成结构什么的。。我当然是一问三不知啦,所以回来之后就自己额外做了一下这个token验证。

组成

jwt主要有三部分组成

  • header,主要就是存放了你的token类型和你的加密方式。
  • playload,一般有签发人,签发时间,过期时间,编号等,这部分是可以添加自己的一些数据进去。
  • signature,要生成这个是需要以上两个字段的,还需要一个密钥,这是只有服务端才知道的一个密钥,生成公式HMACSHA256(
    base64UrlEncode(header) + “.” +
    base64UrlEncode(payload),
    secret)
    上两个字段的base64加上密钥,通过’.’来进行连接,然后再通过hash256进行加密。
    以上三个字段再通过’.’来连接的这样就生成了一个token。

nodejs生成和验证token

我们只需要安装一个jsonwebtoken就可以了。

1
npm install  jsonwebtoken
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
* @Author: Meng Jiawei
* @Date: 2020-06-18 22:36:58
* @LastEditTime: 2020-06-18 23:08:36
* @FilePath: \expressdemo\index.js
*/
const jwt=require('jsonwebtoken')
const playload={
name:'mjw',
admin:true
}
const secret='mengjiawei'
const token=jwt.sign(playload,secret,{expiresIn:'1day'})
console.log(token)

我们使用jwt.sign方法就可以生成这个token,这个方法主要有三个参数,一个就是基本信息,你从前端拿来需要放进token进行加密的东西,然后就是密钥,最后是一个option,我这边是给了一个过期时间为一天。
验证的话我们只要执行下面这一句就行了。

1
2
3
4
5
6
7
jwt.verify(token,'mengjiawei',(err,decoded)=>{
if(err){
console.log('invalid')
return
}
console.log(decoded)
})

如果验证失败就会输出invalid,验证成功就会输出你的token明文信息

在express路由中的使用

我们生成还是跟之前的一样的,在用户登录的时候生成token并返回,我这边写了个简单的例子,成功则返回token不成功则返回失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
router.post('/login',function(req,res,next){
console.log(req.headers)
if(req.body.username=='123456'){
let playload={}
playload.username=req.body.username
playload.password=req.body.password
const secretkey='MMJJWW'
let token=jwt.sign(playload,secretkey,{expiresIn:'1day'})
res.json({
code:200,
msg:'登陆成功',
token:token
})
}else{
res.json({
msg:'错误'
})
}
})

这边可以用postman来测试一下
测试结果:

在这里插入图片描述
在这里插入图片描述

可以看到成功的返回了token
接下来是对每个请求都要进行token验证。我们需要使用express-jwt这个中间件,

1
npm install express-jwt

然后我们可以新建一个check.js

1
2
3
4
5
6
7
8
9
10
/*
* @Author: Meng Jiawei
* @Date: 2020-06-18 23:30:57
* @LastEditTime: 2020-06-18 23:39:28
* @FilePath: \expressdemo\check.js
*/
const expressjwt=require('express-jwt')
const key='MMJJWW'
const jwtauth=expressjwt({secret:key}).unless({path:['/users/login']})
module.exports=jwtauth

这边就是对中间件的配置,只要以对象形式传递一个密钥参数即可,unless就是不对哪个路由生效,我这边设置了登录的时候不需要验证token。
然后在route文件夹下的index.js,配置这个中间件

1
2
3
4
5
router.use(jwt)
router.use((req,res,next)=>{
console.log('这个token被允许了')
next()
})

只要use就可以了,后一个就是如果验证成功了会执行的,next就是去执行接下来的路由。如果验证失败了,会直接告诉前台出错了,前端需要设置拦截器进行处理
我这边他也设置了一个/users/test路由

1
2
3
router.get('/test',function(req,res,next){
res.send('token能正常使用')
})

就简单的返回一句字符串,主要用来测试的。
然后我们前端只要把token放在headers的Authorization字段中就可以了,这个字段是expressjwt规定的,如果不这样设置会报错,说找不到这个字段,然后字段里面的内容要是Bearer+token这个类型的。
比如
Bearer 1eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEyMzQ1NiIsInBhc3N3b3JkIjoibWVuZ2ppYXdlaSIsImlhdCI6MTU5MjQ5NDk1NiwiZXhwIjoxNTkyNTgxMzU2fQ.jBkarDsw71y2oXgG19N3Pad2ou2Oz2UDTwhEp9-cJI0
不然的话也会报错,说你的格式错误了,一定要在token前加入Bearer。
比如我们用postman来对刚才产生的token进行验证一下

在这里插入图片描述
在这里插入图片描述

我们发现成功接收到了返回的数据。
如果我们在改变token,我在之前的token上在加了一个1,结果如下。

在这里插入图片描述
在这里插入图片描述

他就会说这个token是非法的。前端只要添加一个拦截器在结果返回前对错误进行处理即可。

这样我们的token实现基本的权限验证基本就已经完成了,后续还是可以根据自己的需求来完善的。