新版JWT–Json Web Token使用教程
网上那么多教程为啥还写教程?
因为看了很多教程,包括以作者当前时间2021年10月30号,最近一个月检索的文章都是写的旧版本jwt,都是用的基于3系列开头的版本。而作者提交到github上面也是旧版本就会给你报一个安全警告
那上面那段话什么意思喃?就是jwt低于这个版本,别人可以构造字符串数组,绕过权限检查。非常严重的一个安全问题。所以作者就去官方github,看文档,升级到了4.0系列。变化还是非常大的,不仅项目迁移到新仓库,名字也改了。网上绝大多数写的是老版本,所以想写个新版jwt 教程。
什么是JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWT构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload,),第三部分是签证(signature).
JWT使用
在使用JWT我们通常关心载荷就行了,头部是token标识以及选用的算法,签证是验证token有没有被更改。
JWT自带的载荷
旧版JWT载荷叫做StandardClaims,和新版自带载荷定义上没啥区别,有区别的话,就是签发时间,超时时间,时生效时间类型改变了,由原来的的int64变为 *NumericDate类型了。而这个类型又是time类型。
新版本JWT自带载荷
//新版本JWT自带载荷
type RegisteredClaims struct {
Issuer string `json:"iss,omitempty"`//签发者
Subject string `json:"sub,omitempty"`//签发主题
Audience ClaimStrings `json:"aud,omitempty"`//接收者
ExpiresAt *NumericDate `json:"exp,omitempty"`//过期时间
NotBefore *NumericDate `json:"nbf,omitempty"`//生效时间
IssuedAt *NumericDate `json:"iat,omitempty"`//签发时间
ID string `json:"jti,omitempty"`
}
type NumericDate struct {
time.Time
}
旧版本自带载荷
//旧版本
type StandardClaims struct {
Audience string `json:"aud,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Id string `json:"jti,omitempty"`
IssuedAt int64 `json:"iat,omitempty"`
Issuer string `json:"iss,omitempty"`
NotBefore int64 `json:"nbf,omitempty"`
Subject string `json:"sub,omitempty"`
}
我们一般常用就是过期时间,签发时间,生效时间,当我们给token 设置了过期时间后,比如设置7天,当这个token创建后,7天这个时间,这个token就会失效,签发时间是记录当前token是多久创建的,生效时间,表示这个token可以提前创建出来,但是只有到指定时间才会有效。
除了自带的载荷,一般我们也会自定义一些数据在载荷中,放入token中,当客户端请求服务器后,服务器会解析token,拿到里面的自定义信息。
新版本JWT使用例子
package main
import (
"errors"
"github.com/golang-jwt/jwt/v4"
"time"
)
//自定义载荷
type Claims struct {
UID string
jwt.RegisteredClaims//jwt自带载荷
}
//构建载荷
func BuildClaims(uid string, ttl int64) Claims {
return Claims{
UID: uid,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(ttl*24) * time.Hour)), //过期时间
IssuedAt: jwt.NewNumericDate(time.Now()), //签发时间
NotBefore: jwt.NewNumericDate(time.Now()), //生效时间
}}
}
//生成token config.Config.TokenPolicy.AccessExpire是读取配置文件中设置token的过期时间,可用正整数数字代替
func CreateToken(userID string) (string, error) {
claims := BuildClaims(userID, config.Config.TokenPolicy.AccessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(config.Config.TokenPolicy.AccessSecret))
return tokenString, err
}
//config.Config.TokenPolicy.AccessSecret 是读取配置文件中token的秘钥,可以用任意字符串代替
func secret() jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) {
return []byte(config.Config.TokenPolicy.AccessSecret), nil
}
}
//解析token
func ParseToken(tokenss string) (claims *Claims, err error) {
token, err := jwt.ParseWithClaims(tokenss, &Claims{}, secret())
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, errors.New("that's not even a token")
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
return nil, errors.New("token is expired")
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, errors.New("token not active yet")
} else {
return nil, errors.New("couldn't handle this token")
}
}
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("couldn't handle this token")
}
上面自定义载荷结构体,是可以放自己定义的数据,同时集成了jwt自带载荷,当我们调用创建token,传入参数,就能生成token下发到请求客户端,或者自己生成测试。当我们需要检验传来的token的时候,判断是否是有效token,就调用ParseToken方法。
本文介绍了由于旧版JWT存在的安全问题,作者更新到新版JWT并详细讲解了新版本的变化。JWT(JsonWebToken)是一种用于身份验证的标准,文章详细阐述了JWT的构成、使用方法以及如何设置过期时间等核心概念。通过示例代码展示了如何在Go语言中创建和解析JWT,同时强调了新版本中时间类型的变化。
5万+





