JWT

2 min

JWT

token做法额外增加了token.sig,即增加了cookie 数量,数据本身也没有规范的格式,所以 JSON Web Token 横空出世了。

img

证明合法性

选取非对称加密,用公钥验证签名。服务器用私钥签名,当请求到来时候,再用公钥验证。

  • 未被篡改:接收方通过验证签名来确保JWT的内容完整无误。

  • 由可信任的发送方生成:由于只有合法发送方才拥有签名所需的密钥,签名验证成功意味着JWT确实来自可信任的发送方。

时序图

img

Eg.

package utils

import (
    "DiTing-Go/global"
    "github.com/dgrijalva/jwt-go"
    "github.com/pkg/errors"
    "github.com/spf13/viper"
    "time"
)

// 从配置文件中获取JWT的密钥
var jwtSecret = []byte(viper.GetString("jwt.secret"))

// Claims结构体用于JWT的载荷部分
type Claims struct {
    Uid                int64 `json:"uid"` // 用户ID
    jwt.StandardClaims       // 标准声明
}

// GenerateToken 生成token
// uid 用户ID
// 返回生成的token字符串和错误信息
func GenerateToken(uid int64) (string, error) {
    nowTime := time.Now()                           // 当前时间
    expireTime := nowTime.Add(24 * 360 * time.Hour) // 过期时间为360天后

    claims := Claims{
       uid,
       jwt.StandardClaims{
          ExpiresAt: expireTime.Unix(), // 过期时间
          Issuer:    "diting-go",       // 签发者
       },
    }

    // 使用指定的签名方法和载荷生成token
    tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    token, err := tokenClaims.SignedString(jwtSecret) // 使用密钥签名token
    if err != nil {
       global.Logger.Errorf("generate token failed: %v", err) // 记录生成token失败的错误
    }
    return token, err
}

// ParseToken 解析token
// tokenString 待解析的token字符串
// 返回解析后的Claims和错误信息
func ParseToken(tokenString string) (*Claims, error) {
    // 解析token并验证签名
    token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (i interface{}, err error) {
       return jwtSecret, nil // 返回密钥进行签名验证
    })
    if err != nil {
       return nil, err
    }
    // 校验token是否有效
    if claims, ok := token.Claims.(*Claims); ok && token.Valid {
       return claims, nil
    }
    return nil, errors.New("invalid token") // 返回无效token的错误
}