结构
JSON Web Token 由.
分隔为三个部分,分别是:
Header
Payload
Signature
如Header.Payload.Signature
。
Header
Header 由两部分组成,签名算法和令牌类型,签名算法有 HMAX SHA256 或 RSA 等,令牌类型则是 JWT。如下所示:
{
"alg": "HS256",
"typ": "JWT"
}
Payload
Payload 里存放的是实际传送的数据。其中有几个字段是官方推荐的,括号中是字段的全称:
- iss(Issuer)
- sub(Subject)
- aud(Audience)
- exp(Expiration Time)
- nbf(Not Before)
- iat(Issued At)
- jti(JWT ID)
当然,以上字段并非强制使用,完全可以自定义字段。例如:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Signature
签名需要指定算法。以下是默认的 HMACSHA 算法签名方式,将以上的 Header 和 Payload 经过 base64Url 编码,再用.
进行拼接,secret 指定的密钥。签名用于验证消息没有被更改。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
合并
将以上的 Header、Payload、Signature 分别进行 base64Url 编码,用.
进行拼接,最后形成 JSON Web Token。
实现
以下代码是官网示例的简版实现,使用了默认算法 HS256 进行签名。
// jwt.go
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"strings"
)
type Header struct {
Alg string `json:"alg"`
Typ string `json:"typ"`
}
type Payload struct {
Sub string `json:"sub"`
Name string `json:"name"`
Iat int `json:"iat"`
}
func main() {
header := Header{
"HS256",
"JWT",
}
headerSli, err := json.Marshal(header)
if err != nil {
log.Fatal(err)
}
headerStr := base64.RawURLEncoding.EncodeToString(headerSli)
payload := Payload{"1234567890", "John Doe", 1516239022}
payloadSli, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
payloadStr := base64.RawURLEncoding.EncodeToString(payloadSli)
hp := bytes.Join([][]byte{[]byte(headerStr), []byte(payloadStr)}, []byte{'.'})
secret := []byte("Hello world")
h := hmac.New(sha256.New, secret)
_, err = h.Write(hp)
if err != nil {
log.Fatal(err)
}
signStr := base64.RawURLEncoding.EncodeToString(h.Sum(nil))
jwt := strings.Join([]string{headerStr, payloadStr, signStr}, ".")
fmt.Println(jwt)
}
以上代码结果如下,可以跟官网的结果进行对比验证。
$ go run jwt.go
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.O0t7UHnKu0-Q30CpQa1-Oi9TdUQ-fSktY3M4G6O0mPU
服务器在生成 jwt 时,对生成的 jwt 和 secret 进行绑定保存,在客户端将 jwt 回传时即能过 base64 解码获取对应原内容进行验证。
由于 JSON Web Token 保存在客户端,所以不要存放敏感数据。