JWT 介绍
JWT 即 JSON Web Token,是用 JSON 形式安全传输信息的方法。
我们可以在 jwt.io 上在线解析 token,可以清楚看懂 JWT 的数据结构。
对 JWT 解码,可以得到以下内容:
- Header:TOKEN 的类型,就是JWT,签名的算法,如 HMAC、 SHA256
- Payload:携带的信息,比如用户名、过期时间等,一般叫做 Claim
- Signature:签名,是由header、payload 和你自己维护的一个 secret 经过加密得来的。
JWT 可以设置过期时间,它的应用主要有:
-
Access Token:添加到 HTTP 请求的 header 中,进行用户认证。加上过期时间可以让 token 被恶意截获后,黑客只有短暂的时间攻击。
-
Refresh Token:用来给客户端申请新的 Access Token 或者 Refresh Token。比 Access Token 有更长过期时间。
HttpOnly
Go语言中 JWT 的生成、验证
使用 jwt-go 库生成 JWT。
import github.com/dgrijalva/jwt-go
func CreateToken(uid, secret string) (string, error) {
at := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"uid": uid,
"exp": time.Now().Add(time.Minute * 15).Unix(),
})
token, err := at.SignedString([]byte(secret))
if err != nil {
return "", err
}
return token, nil
}
通常客户端传输 JWT 是通过 header 中的 Authorization 字段,好处是避免了 CORS攻击。并且使用 Bearer 模式。也就是:
Authorization: Bear eyJhbGciO...
在 grpc 中,可以将 JWT 放在 metadata 中:
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", "Bearer "+token))
res, _ := client.Call(ctx, ..)
在服务端的验证:
// 忽略 ok为假的情况
incomingContext, ok := metadata.FromIncomingContext(ctx)
value, ok := incomingContext["authorization"]
uid, err := ParseToken(value[0])
解析也需要用 jwt-go 库的函数。
// token: "eyJhbGciO..."
func ParseToken(token string, secret string) (string, error) {
claim, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return "", err
}
if uid, ok := claim.Claims.(jwt.MapClaims)["uid"].(string); ok {
return uid, nil
}
return "", fmt.Errorf("fail parse")
}