Gin 教程叕来了(说好的大结局呢?),此次主要是来讲明 JWT
存在的一些问题和解决方案。若是你还不知道 JWT
是什么,建议了解一下,也能够翻翻前面的文章看看。git
上次写 JWT
的时候,和群里的小伙伴讨论,有小伙伴提出了一些问题,用户修改密码或者注销帐户怎么办?github
是啊,怎么办?redis
咱们都知道 JWT
是否有效,靠的是失效时间,并且服务器不对用户 JWT
进行保存,也就是一旦签发了的 JWT
,服务器失去了对其的控制权,只能等其过时而失效。若是这样,那么用户修改密码或者注销以后,以前的 JWT
仍旧还能够使用,那么就会带来安全风险。数据库
因而乎,我默默的打开了百(gu)度(ge)浏览器
🙄🙄🙄🙄🙄🙄安全
大家为何要把 JWT
存在 redis
里?服务器
这是什么操做?一旦服务器去保存 JWT
,还用什么 JWT
?普通 token
就彻底能够了啊,何须画蛇添足。ui
以上就是咱们在使用 JWT
的时候产生的问题。加密
既然有了问题,就要解决。spa
再次回顾一下 JWT
的使用流程。
浏览器发出登陆请求,将帐号和密码提交到服务器;
服务器建立 JWT
而且加密(并非所有加密,仅仅加密 VERIFY SIGNATURE
);
将 JWT
返回浏览器;
访问须要受权的接口,将 JWT
携带在Header;
校验 JWT
,而且从 JWT
获取 JWT
;
响应浏览器。
上面的六个步骤就是 JWT
使用的过程。服务器只作了两步,生成 JWT
和校验 JWT
。而咱们解决上述提出的问题,就在服务器端解决。
咱们都知道在加密的时候服务器端会保存一个密钥,而校验解密的时候就须要这个密钥,这个密钥就是咱们解决该问题的 KEY 。
若是咱们把密钥设成动态的,用户密码修改或者注销的时候,该密钥就会发生改变,那么以前签发的 JWT
没法使用新的密钥来解密了,也就意味着以前的密钥已经失效了。而这个动态密钥应该保证独立,每一个用户的密钥应该是不同的,该用户的密钥只负责该用户的 JWT
。
因而乎,问题彷佛已经解决了,咱们能够在数据库用户表中设置一个单独的字段来标识,每次发生密码修改或者帐号注销的时候,只须要修改该字段就能够保证以前的JWT
失效。或者使用用户的密码做为密钥。
UserHandler.go
// 经过密码和保留字段加密
var jwtSecret = []byte(config.Secret + u.Password)
token, err := tokenClaims.SignedString(jwtSecret)
复制代码
其中 config.Secret
是咱们服务器上的固定密钥。
Auth.go
// 分割出来载体
payload := strings.Split(token, ".")
bytes, e := jwt.DecodeSegment(payload[1])
if e != nil {
println(e.Error())
}
content := ""
for i := 0; i < len(bytes); i++ {
content += string(bytes[i])
}
split := strings.Split(content, ",")
id := strings.SplitAfter(split[2], ":")
i := strings.Split(id[1], "\\u")
i = strings.Split(i[1], "\"")
ID, err := strconv.Atoi(i[0])
if err != nil {
println(err.Error())
}
user := model.User{}
user.ID = uint(ID)
u := model.User.QueryById(user)
jwtToken, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{},
func(token *jwt.Token) (i interface{}, e error) {
return []byte(config.Secret + u.Password), nil
})
复制代码
这里就不展现所有代码了。你们能够看 Github gin_jwt_2 分支上查看。
欢迎各位大佬关注。