jwt库很多了 各有各的优势 有些库是不维护了
我选择了 github.com/golang-jwt/jwt 库
获取命令:go get -u github.com/golang-jwt/jwt/v4
Header
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等
{ | |
'typ': 'JWT', | |
'alg': 'HS256' | |
} |
Payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
- 标准中注册的声明
- 公共的声明
- 私有的声明
jwt.StandardClaims 标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息
私有定义的内容根据自己业务需要来,这里简单加了UID
type AuthClaim struct { | |
UID int64 `json:"uid"` | |
jwt.StandardClaims | |
} |
Signature 签名
secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
var Secret = "私钥" | |
var hmacSampleSecret = []byte(Secret) |
生成token
生成了两个小时过期时间的token
const TokenExpireDuration = 2 * time.Hour //过期时间 | |
func New(uid int64) (tokenStr string) { | |
var authClaim AuthClaim | |
authClaim.UID = uid | |
authClaim.StandardClaims.ExpiresAt = time.Now().Add(TokenExpireDuration).Unix() | |
token := jwt.NewWithClaims(jwt.SigningMethodHS256, authClaim) | |
tokenString, _ := token.SignedString(hmacSampleSecret) //私钥加密 | |
return tokenString | |
} |
解析token
func Parse(tokenString string) (auth AuthClaim, Valid bool) { | |
token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | |
// Don't forget to validate the alg is what you expect: | |
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { | |
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) | |
} | |
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key") | |
return hmacSampleSecret, nil | |
}) | |
Valid = token.Valid//token是否有效 true有效 false无效 | |
if claims, ok := token.Claims.(jwt.MapClaims); ok && Valid { | |
auth.UID = int64(claims["uid"].(float64)) //自定义的UID | |
auth.ExpiresAt = int64(claims["exp"].(float64)) //过期时间 | |
} | |
return | |
} |