go实现JWT | 青训营笔记

44 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

jwt结构

JSON Web Token 由三部分组成,以点(.)分隔,分别是:

  • Header(标头)
  • Payload(有效负载)
  • Signature(签名)

因此,JWT 通常如下所示:

xxxxxx.yyyyyyy.zzzzzzzz

Header

Header 通常由两部分组成:

  • token 的类型,这里是 JWT
  • 使用的签名算法,比如 HMAC、SHA256 或 RSA。

例如:

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

然后,将此 JSON 以 Base64Url 编码,形成 JWT 的第一部分。

Payload

token 的第二部分是有效负载,其中包含 Claims(声明)。Claims 是有关实体(通常是用户)和其他数据的声明 举一个有效负载的例子:

{
  "sub": "221122112",
  "name": "Mohamd Lawand",
  "admin": true,
  "exp": 15323232,
  "iat": 14567766 // 该 token 的签发时间
}

然后,对有效负载进行 Base64Url 编码,形成 JSON Web Token 的第二部分。

除非将其加密,否则不要将机密信息放入 JWT 的 Payload 或 Header 元素中。

签名

签名使我们能够验证 token 是否有效和没被篡改。它的工作方式是获取 token 的前两部分,将 Header 和 Payload 分别编码为 Base64,然后将它们用 “.” 连接起来。然后,获取在第一部分(Header)中提供的算法并应用于上面的连接结果。

gin封装实现jwt

package main

import (
    "fmt"
    "net/http"
    "time"

    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
)

//自定义一个字符串
var jwtkey = []byte("www.xxx.com")
var str string

type Claims struct {
    UserId uint
    jwt.StandardClaims
}

func main() {
    r := gin.Default()
    r.GET("/set", setting)
    r.GET("/get", getting)
    //监听端口默认为8080
    r.Run(":8080")
}

//颁发token
func setting(ctx *gin.Context) {
    expireTime := time.Now().Add(7 * 24 * time.Hour)
    claims := &Claims{
        UserId: 2,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expireTime.Unix(), //过期时间
            IssuedAt:  time.Now().Unix(),
            Issuer:    "xxx",  // 签名颁发者
            Subject:   "user token", //签名主题
        },
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    // fmt.Println(token)
    tokenString, err := token.SignedString(jwtkey)
    if err != nil {
        fmt.Println(err)
    }
    str = tokenString
    ctx.JSON(200, gin.H{"token": tokenString})
}

//解析token
func getting(ctx *gin.Context) {
    tokenString := ctx.GetHeader("Authorization")
    //vcalidate token formate
    if tokenString == "" {
        ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
        ctx.Abort()
        return
    }

    token, claims, err := ParseToken(tokenString)
    if err != nil || !token.Valid {
        ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
        ctx.Abort()
        return
    }
    fmt.Println(111)
    fmt.Println(claims.UserId)
}

func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
    Claims := &Claims{}
    token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) {
        return jwtkey, nil
    })
    return token, Claims, err
}