持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
jwt的特点
简洁,不占用服务端存。
cookie和session
http协议无状态的,每次请求对于服务端来说都是一个独立的,早期保存用户信息使用的是cookie和session,cookie存储在客户端,存一个sessionid每次请求时携带上,session存储在后端,每次通过请求携带过来的sessionId去找对应的session数据,判断用户信息。
这种方式存在一些弊端,session是基于cookie的。cookie不支持跨域\用户禁用cookie时\用户使用的是移动设备,一但cookie无法使用,那么session也会无法使用。
token
token的出现解决了这一问题,他将鉴权信息放在请求头部,在http头部拿到信息后进行用户验证,这就解决了cookie无法使用时的验证用户信息的问题
jwt
jwt是对token的进一步改造。它与token相比, token数据存在服务端, jwt存储在客户端。jwt不会占用服务器资源,但是他会消耗cpu的处理(与token相比)
jwt 的组成
jwt由头部(head)、用户信息(claim)、签名(signal)三个部分通过.拼接后再用base64编码成的一段字符串。
jwt的交互过程
-
jwt的获取
客户端发送身份信息到服务端,服务端校验完成后将部分用户信息加密,生成一个jwt字符串给客户端。客户端获得一个jwt字符串。
2. 业务请求中携带上jwt
获取到jwt字符串后,每次请求都携带上它,用于标识身份。
jwt在服务端的验证过程
服务端获取到jwt字符串后,
- 先将字符base64解码,拆分成三部分:
head、claim、sign。 head中存放了sign的加密方式,通过将cliam与服务端的密钥(secret)通过head中的加密方式加密,生成一个sign2- 将
sign2与客户端的sign比较(sign2 == sign ?),如果一致说明是签发的jwt。不一致则说明发送的字符串有问题 - 再检验jwt的时效,是否过期
在golang使用
命令行下安装jwt模块
go get github.com/golang-jwt/jwt/v4
生成jwt
-
声明claim,存储
用户信息和jwt信息 -
生成token对象
-
使用token对象的
SignedString方法生成最终的token字符串
// 略...
// 创建 Claims ,MyCliams是自定义的jwt结构体
claims := &MyCliams{
params.Name,
params.Age,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), // 过期时间
Issuer: "", // 签发人
},
}
// 生成token对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 生成签名字符串
tokenstr, err := token.SignedString(secret)
// 略...
验证jwt
// 略...
/**
@ params.Token 是客户端发送过来的token字符串
@ &claim 是存放结果的结构体
*/
token, err := jwt.ParseWithClaims(params.Token, &claim, func(token *jwt.Token) (i interface{}, err error) {
// secret 是服务端加密使用的密钥,生成时也是用这把
return secret, nil
})
// 返回的是接口,将它断言为自定义结构体指针
cl, ok := token.Claims.(*MyCliams);
// 略...
客户端重复申请jwt问题
客户端一直访问登录接口,服务端因为没有记录,无法判断用户是否登录过。
总结
jwt是随着不同业务需要,演化而来。相比于cookie和token,jwt并不占用服务器存储,切安全,能够支持单点登录。但也是它不占用服务器资源的有点,导致它对jwt的控制不完整,他只能颁发而无法主动销毁,除非在服务端存下记录。