jwt加密是一种简单的加密,虽说是加密,但是建议大家不要将自己的密码放在jwt加密的行列,因为会导致泄露,jwt有加密就有解密,我们需要用到两个模块,express-jwt jsonwebtoken ;
先来了解一下到底jwt是什么,其实就是一种字符串,只是有Header.Payload.Signature三部分组成的,不过只有Payload存储的使我们的信息数据,其他两部分是jwt用来加密的机制,可以有效的防止别人破解;
接下来就是如何实现这个加密:
1、导入安装模块:
npm i express-jwt jsonwebtoken
//2.2 安装并导入jwt模块
const expressjwt = require('express-jwt')//模块作用就是将jwt字符串还原成json字符串
const jsontoken = require('jsonwebtoken')//模块作用就是将json字符串加密成一个jwt对象
同样,我们是在服务器上对客户端提供的账户密码进行处理,我们就拿用户名来加密好了,之前我们学过如果创建服务器和如何提交表单,如果不记得可以去前面看;
2、在加密的过程之中,我们需要一个秘钥,这个秘钥本质就是一个字符串,一个自定义字符串,越复杂越难让别人破解,所以我们先定义好一个比较复杂秘钥:
//2.1 创建一个秘钥用来加密
const secretkey = 'tonysecret^_^'
3、 加密需要用到jsonwebtoken模块的sign()方法,这个方法有三个参数,第一个是我们要加密的对象,注意是一个对象,不是一个字符串,然后第二个是我们定义的秘钥,第三个是我们的有效期,也是一个对象,我们的信息对象可以用客户端提交过来的表单数据req
//2.4 创建一个token对象
const mytoken = jsontoken.sign({username:req.body.username},secretkey,{expiresIn:'1h'})
我这里用到了提交表单里面的用户名,然后有效期是一个小时;
4、当然,我们加密之后就需要解密,也就是当我们客户端拿到服务器给的token时候,可以发一个带有Authorization响应头的请求,这样就可以拿到我们的用户名:
const mytoken = jsontoken.sign({username:req.body.username},secretkey,{expiresIn:'1h'})
//2.5 将加密的jwt返回给客户端
res.send({
status:200,
message:'登陆成功',
username:mytoken
})
当我们加密之后,客户端会拿到一个字符串是jwt类型,也就是Header.Payload.Signature类型:
这就是我们拿到的username,经过了加密处理变成了jwt格式,如果我们要解密,就可以发起一个get请求,这个请求就带有这个token的,也就是username后面的这一串字符串,
可以看到,我们在postman里面发起带有这个响应头的get请求我们可以拿到经过解析的对象;还有一个要注意,在我们填响应头数据的时候需要在我门token前面加一个Bearer空格,不然的话请求不会成功,key的话就是我们的Authorization类型。
5、关于服务器放对带有token的响应头的解码,因为这个响应头其实就携带这这个username的信息,所以我们解码之后就可以拿到,我们需要用到express-jet模块,使用下面的方法可以解析jwt字符串并且将解析出来的对象挂载到req上,对象名为user所以我们可以通过res.send()直接将req.user发送给客户端,那么客户端就可以拿到这个信息了:
//3.2 注册一个全局中间件对jwt进行解析
app.use(expressjwt({secret:secretkey,algorithms:['HS256']}).unless({path:[/^\/api\//]}))
//3.1 注册一个get路由,用来获取我们加密的对象
app.get('/admin/logininfo',(req,res)=>{
console.log(req.user)
res.send({
status:200,
message:'获取信息成功',
username:req.user
})
})
expressjwt()方法的参数就是我们的秘钥,是一个对象要注意,对象的属性有我们的秘钥,当然在express-jwt6.0版本之后我们要加上后面algorithms:['HS256']这句话,不然会报一个algroithms未定义的错误,这是固定写法所以还是加上,而unless()这个方法只是不需要权限访问,里面也是一个对象,一个含有path属性的对象,path属性是一个数组,里面可以用正则表达式来筛选哪一些请求不需要访问权限,我这里是筛选api接口不需要权限;注意我们的解码放在我们的get路由前面就可以了,如果放在太前会出现解析问题,因为我们还没有加密就解析的话会出错、
6、为了保证安全运行,我们需要在后面添加一个错误捕获路由,还记得吗,我们之前讲过专门捕获错误的路由:
//4.1 注册一个中间件路由将错误捕获
app.use((err,req,res,next)=>{
if(err.name == 'UnauthorizedError'){
return res.send({
status:401,
message:'无效token'
})
}
res.send({
status:401,
message:'其他错误'
})
})
这个路由很简单,如果我们错误名字为UnauthorizedError就说明是一个解析错误的问题,也就是起到一个分析是否是解析错误的错误捕获路由;
回顾我们之前的session认证机制,相比之下我们的jwt要更加流行,因为jwt弥补了session不嫩跨域访问的问题,而且我们在学习中可以发现,我们加密的数据会到达客户端,也就是存在了客户端,而服务器就起到一个加密和解密的作用。
好了,这一期就到这里;
下面我分享所有代码:
//1.1 安装并导入模块
const express = require('express')
const session = require('express-session')
//2.2 安装并导入jwt模块
const expressjwt = require('express-jwt')//模块作用就是将jwt字符串还原成json字符串
const jsontoken = require('jsonwebtoken')//模块作用就是将json字符串加密成一个jwt对象
//1.2 创建一个服务器
const app = express()
//1.3 使用编码中间件
app.use(express.urlencoded({extended:false}))
//2.1 创建一个秘钥用来加密
const secretkey = 'tonysecret^_^'
//2.3 注册一个post路由
app.post('/admin/login',(req,res)=>{
if(req.body.username == 'tony' && req.body.password == '000000'){
//2.4 创建一个token对象
const mytoken = jsontoken.sign({username:req.body.username},secretkey,{expiresIn:'1h'})
//2.5 将加密的jwt返回给客户端
res.send({
status:200,
message:'登陆成功',
username:mytoken
})
}else{
res.send({
status:401,
message:'登录失败'
})
}
})
//3.2 注册一个全局中间件对jwt进行解析
app.use(expressjwt({secret:secretkey,algorithms:['HS256']}).unless({path:[/^\/api\//]}))
//3.1 注册一个get路由,用来获取我们加密的对象
app.get('/admin/logininfo',(req,res)=>{
console.log(req.user)
res.send({
status:200,
message:'获取信息成功',
username:req.user
})
})
//4.1 注册一个中间件路由将错误捕获
app.use((err,req,res,next)=>{
if(err.name == 'UnauthorizedError'){
return res.send({
status:401,
message:'无效token'
})
}
res.send({
status:401,
message:'其他错误'
})
})
//1.4 打开服务器
app.listen(8080,()=>{
console.log('server running at http://127.0.0.1:8080')
})