JWT原理及Golang语言的简单应用
高能预警
- 本文参考JWT官方网站介绍:jwt.io
- 本文引用Golang库:github.com/dgrijalva/jwt-go
正文
关于JWT
JWT
全名 Json Web Token,顾名思义:即 用于Web传输 加密的JSON对象过程时的令牌。
一般是这样形状的:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE2NDE5ODk4NDgsInVzZXJuYW1lIjoiYSJ9.zW11Cq8QNHTHJMUResrQeKVRTNLUlDymVsTPy2ororI
那我们如何从这串乱码中 得到我们想要的数据呢?
分解JWT
我们通过观察这串乱码发现,其被“.”分割成了三部分,下面博主将分别解释这三段内容,请君继续阅读
JWT第一部分:Header
我们使用base64
解密第一段:
func main() {
decodeString, _ := base64.StdEncoding.DecodeString(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
fmt.Println(string(decodeString))
}
得到了这样的结果:
{"alg":"HS256","typ":"JWT"}
- 我们通常把JWT的这部分称之为
Header
,也就是 头部,typ
字段表示令牌的类型,即这是一个“JWT”;
和一个正在使用的签名算法,即HS256
。当我们把这些信息组成一个JSON对象
并使用base64
加密算法加密后,即得到JWT的第一部分。
JWT第二部分:Payload
同样使用base64
解密第二段,得到了这样的结果:
{"authorized":true,"exp":1641990483,"username":"a"}
实际上,这个JSON对象是我们自己定义的,代码如下:
func CreateJWT(username string, key string) (string, error) {
c := jwt.MapClaims{}
c["authorized"] = true
c["username"] = username
c["exp"] = time.Now().Add(600 * time.Second).Unix()
t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
token, err := t.SignedString([]byte(key))
if err != nil {
return "", err
}
return token, err
}
-
我们通常把JWT第二部分称之为
Payload
,也就是 有效载荷,里面包含了我们自己定义的内容(通常为我们想要认证的字段),并进行base64
加密。最终得到了JWT的第二部分。 -
在这里,我们可以看到,首先创建了一个
jwt.MapClaims{}
类型的变量,实际上他就是map[string]interface{}
的别名,我们可以直接塞入自定义数据。
// Claims type that uses the map[string]interface{} for JSON decoding
// This is the default claims type if you don't supply one
type MapClaims map[string]interface{}
到这里读者们可能会想到,既然jwt的内容这么“暴露”,我们该怎样使用它来建立信任呢?这就到了JWT最关键的第三部分——Signature
了。
JWT第三部分:Signature
-
这部分通常由JWT的
header.payload
部分,加上我们自己定义的密钥,通过头部声明的加密算法(第一部分的typ
字段的值)加密后,得到了JWT的第三部分:签名。 -
把以上三部分放在一起,以“.”分隔的Base64-URL字符串,就是我们生成的完整的JWT了。
可以在HTML
和HTTP
环境中轻松传递,同时与基于XML
的标准(如SAML
)相比更加“紧实”。
小结
不论是我们自定义的密钥,还是JWT的签发过程,都是在服务端完成的,也就是说在我们保护好密钥的前提下,JWT是可以完成权限鉴定的。
附图
将JWT用于访问 API 或其他资源的过程
感谢阅读。