什么是 JWT

JWT is short for JSON Web Token

INTRO

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

可见,JWT主要是用来在不同组间安全传输 JSON 信息。
自我包含,可被信任。

JWT 结构

三部分组成,由.分割

  • 头部(加密信息)
  • 负荷(需要传输的 JSON)
  • 签名(验证使用)

最终的结果类似于:xxxxx.yyyyy.zzzzz

{
  "alg": "HS256",
  "typ": "JWT"
}

由加密算法和 JWT 标识组成

负荷

这里就是你要传输的json结构体了,不建议传输私密信息,JWT 不是干这个的。

签名

根据上面两个内容来生产一个签名,签名用来验证消息发送者的真伪。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);

上面的就是签名,其中secret是私钥,需要自己保管好。

最后讲上面三个内容按照先进行base64之后再按照aa.bb.cc组合在一起就是一个 JWT 了,看上去还是挺简单的。

需要记住的是,payload只是经过简单base64因此不能传输私密内容。

Goland 的坑

github上面的 jwt 包,一般都是使用map[string]interface{}来装载任意json结构体。

在进行payload这一步的时候,会用到json.Marshal()方法来产生json字符串。

由于使用到了map,总所周知,map的遍历是无序的,因此同一个json结构,可能会参数不同的JWT出来,如果服务器对此收到的payload字段位置没有要求,这样做是没有问题。但是如果,有要求的话,就会产生问题。

为此,解决方案是放弃map方案,使用struct结构体,这样的不便之处就是,必须为每一个json结构定义一个struct,按照需要的字段定义即可,这样序列化结构体的时候就可以保留字段的信息。

虽然会有点不方便,不过确实是一个很不错的解决方案。

附,简易的jwt实现

package jwt

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
)

type HS256 struct {
    Claim interface{}
    Key   string
}

type header struct {
    Alg string `json:"alg"`
    Typ string `json:"typ"`
}

func (h HS256) header() *header {
    return &header{
        Typ: "JWT",
        Alg: "HS256",
    }
}

func (h HS256) Encode() (string, error) {
    header, _ := json.Marshal(h.header())
    jsonHeader := base64.RawURLEncoding.EncodeToString(header)
    claim, err := json.Marshal(h.Claim)
    if err != nil {
        return "", err
    }
    jsonClaim := base64.RawURLEncoding.EncodeToString(claim)
    unsigned := jsonHeader + "." + jsonClaim
    hh := hmac.New(sha256.New, []byte(h.Key))
    if _, err := hh.Write([]byte(unsigned)); err != nil {
        return "", err
    }
    signed := base64.RawURLEncoding.EncodeToString(hh.Sum(nil))
    return jsonHeader + "." + jsonClaim + "." + signed, nil
}

使用示例

func main(){

    j := jwt.HS256{
        Claim: struct {
            P   string `json:"p"`
            T   int64  `json:"t"`
            B   string `json:"b"`
            W   int    `json:"w"`
            Iat int64  `json:"iat"`
        }{
            P:   "11",
            T:   1583075639000,
            B:   "12054",
            W:   1000,
            Iat: 1583075639,
        },
        Key: jwtKey,
    }

    fmt.Println(j.Encode())
}

END

Last modification:March 15th, 2020 at 01:15 pm
要饭啦~