JWT认证机制
什么是JWT
JSON Web Token,是目前最流行
的跨域认证解决方案
JWT的工作原理
总结:用户的信息通过Token字符串的形式,保存在客户端浏览器中,服务器通过还原Token字符串的形式来认证用户的身份。
JWT的组成部分
JWT通常由三部分组成,分别是Header(头部),Payload(有效载荷),Signature(签名)。 三者之间使用英文的“.”分隔,格式如下
Header.Payload.Signature
- Payload部分
才是真正的用户信息
,它是用户信息经过加密之后生成的字符串。 - Header和Signature是
安全性相关
的部分,只是为了保证Token的安全性
JWT的使用方式
客户端收到服务器返回的JWT之后,通常会将它储存在localStorage
或sessionStorage
中。
此后,客户端每次与服务器通信,都要带上这个JWT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中
,格式如下:
Authorization:Bearer <token>
- 安装JWT相关的包 运行如下命令,安装如下两个JWT相关的包:
npm install jsonwebtoken express-jwt
其中:
- jsonwebtoken 用于生成JWT字符串
- express-jwt 用于将JWT字符串解析还原成json对象
- 导入JWT相关的包
//导入express模块
const express = require('express')
//创建express的服务器实例
const app = express()
//安装并导入JWT相关的两个包
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
//允许跨域资源共享
const cors = require('cors')
app.use('cors()')
- 定义secret秘钥
为了
保证JWT字符串的安全性
,防止JWT字符串在网络传输过程中被别人破解,我们需要定义一个用于加密
和解密
的secret秘钥
- 当生成JWT字符串的时候,需要使用secret秘钥对用户的信息
进行加密
,最终得到加密好的JWT字符串 - 当把JWT字符串解析还原成JSON对象的时候,需要使用secret秘钥
进行解密
//secret 的密钥本质:就是一个字符串
const secretKey = 'yiquersanli( ̄▽ ̄)/'
4.登录成功后生成JWT字符串 调用jsonwebtoken包提供的sign()方法,将用户的信息加密成JWT字符串,响应给客户端
app.post('/api/login',(req,res)=>{
//将req.body请求体中的数据转存为userinfo常量
const userinfo = req.body
//登陆失败
if(userinfo.username !=='admin' || userinfo.password!=='0000000'){
return res.send({
status:400,
message:'登陆失败!',
})
}
//登陆成功
//用户登陆成功之后,调用jwt.sign()方法生成JWT字符串。并通过token属性发送给客户端
//参数1:用户的信息对象
//参数2:加密的密钥
//参数3:配置对象,可以配置当前token的有效期,秒:s,小时:h
//注意:千万不要将密码加密到token字符串中
const tokenStr = jwt.sign({username:userinfo.username},secretKey,{expiresIn:'30s'})
res.send({
status:200,
message:'登陆成功',
//调用jwt.sign()生成JWT字符串,三个参数分别是:用户信息对象,加密秘钥,token有效期
token:tokenStr,//要发送给客户端的token字符串
})
})
- 将JWT字符串还原为JSON对象
客户端每次在访问哪些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将Token字符串发送到服务器进行身份认证。
此时,服务器中可以通过express-jwt这个中间件,自动将客户端发送过来的Token解析还原成JSON对象:
//使用App.use()来注册中间件
//expressJWT({secret:secretKey})就是用来解析Token的中间件
// .unless({path:[/^/api\//]})来指定哪些接口不需要访问权限
//path:[/^/api\//]:以/api/开头的接口都不需要权限即可访问
app.use(expressJWT(secret:secretKey).unless({path:[/^\/api\//]}))
-
使用req.user获取用户信息 当express-jwt这个中间件配置成功后,即可在那些有权限的接口中,使用req.user对象,来访问从JWT字符串中解析出来的用户信息了
-
捕获解析JWT失败后产生的错误 当时用express-jwt解析Token字符串时,如果客户端发送过来的Token字符串
过期
或不合法
,会产生一个解析失败
的错误,影响项目的正常运行。我们可以通过Express的错误中间件
,捕获这个错误并进行相关的处理
app.use((err,req,res,next)=>{
//token解析失败导致的错误
if(err.name === 'UnauthorizedError'){
return res.send({status:401,message:'无效的token'})
}
//其它原因导致的错误
res.send({status:500,message:'未知错误'})
})