golang,go,博客,开源,编程

golang每日一库之jwt-go

Published on with 0 views and 0 comments

jwt-go 是一个用于处理 JSON Web Tokens (JWT) 的 Go 语言库。JWT 是一种开放标准(RFC 7519),用于在各方之间以简洁、URL 安全的方式传递声明。JWT 常用于身份验证和信息交换,尤其在分布式系统中广泛使用。jwt-go 提供了创建、解析和验证 JWT 的功能,使得在 Go 中处理 JWT 变得简单和高效。

1. 安装

首先,通过 go get 安装 jwt-go

go get github.com/golang-jwt/jwt/v4

需要注意的是,jwt-go 已经被社区更新和维护,并且现在采用了版本控制,因此推荐使用 v4 版本。

2. 基本概念

JWT 通常由三个部分组成,格式如下:

Header.Payload.Signature
  • Header:包含了令牌的类型(通常是 JWT)和签名算法(如 HS256RS256)。
  • Payload:包含了声明(Claims),声明是关于实体(通常是用户)和其他数据的声明。
  • Signature:用于验证消息的真实性,防止数据被篡改。它是通过对 Header 和 Payload 进行加密得到的。

3. JWT 的结构

JWT 的结构非常简单,由三部分组成,每部分通过 . 分隔开来:

header.payload.signature
  • Header:通常是一个 JSON 对象,描述签名使用的算法(如 HS256RS256)。例如:

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • Payload:包含 Claims,Claims 是有关实体(通常是用户)和其他数据的声明。常见的标准 Claims 包括:

    • iss(Issuer):签发者。
    • sub(Subject):主题,通常是用户标识符。
    • iat(Issued At):签发时间。
    • exp(Expiration Time):过期时间。
    • aud(Audience):受众。

    示例 Payload:

    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
    
  • Signature:为了生成签名部分,需要将 Header 和 Payload 编码为 Base64 字符串,然后用签名算法(如 HMAC SHA256 或 RSA)对其进行签名,密钥通常由服务端持有。

4. 创建和签名 JWT

jwt-go 提供了非常方便的 API 来创建和签名 JWT。

4.1 创建一个简单的 JWT

以下是一个简单的示例,创建一个 HS256 算法的 JWT:

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

var secretKey = []byte("mySecretKey") // 用于签名和验证的密钥

func main() {
	// 创建一个新的 token
	token := jwt.New(jwt.SigningMethodHS256)

	// 设置声明(Claims)
	claims := token.Claims.(jwt.MapClaims)
	claims["sub"] = "1234567890"
	claims["name"] = "John Doe"
	claims["iat"] = time.Now().Unix()

	// 签名并产生完整的 token 字符串
	tokenString, err := token.SignedString(secretKey)
	if err != nil {
		log.Fatalf("Error signing the token: %v", err)
	}

	fmt.Println("Generated Token:", tokenString)
}
  • jwt.New(jwt.SigningMethodHS256) 创建一个新的 JWT 对象,使用 HS256 签名算法。
  • claims["sub"] = "1234567890" 设置了 JWT 的声明(payload)。
  • token.SignedString(secretKey) 通过提供的密钥签名该 token,并返回最终的 JWT 字符串。

4.2 使用不同的签名算法

jwt-go 支持多种签名算法,例如:

  • HS256:HMAC SHA256
  • RS256:RSA SHA256

例如,使用 RSA 签名算法时:

// 假设你已经有了 RSA 私钥
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(rsaPrivateKey))
if err != nil {
	log.Fatal("Failed to parse private key:", err)
}

token := jwt.New(jwt.SigningMethodRS256)
claims := token.Claims.(jwt.MapClaims)
claims["sub"] = "1234567890"
claims["name"] = "John Doe"
claims["iat"] = time.Now().Unix()

tokenString, err := token.SignedString(privateKey)
if err != nil {
	log.Fatal("Failed to sign token:", err)
}

fmt.Println("Generated RSA Token:", tokenString)

在这种情况下,你需要先通过 RSA 私钥来签名 JWT,而不是使用 HS256 算法的对称密钥。

5. 解析和验证 JWT

解析和验证 JWT 同样也非常简单。你可以使用 jwt-go 来验证 JWT 的签名是否有效,并获取其 payload。

5.1 解析 JWT

下面是如何解析一个 JWT,并验证它的签名:

package main

import (
	"fmt"
	"log"

	"github.com/golang-jwt/jwt/v4"
)

var secretKey = []byte("mySecretKey")

func main() {
	tokenString := "your_jwt_token_string_here" // 从客户端获取的 JWT 字符串

	// 解析并验证 JWT
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 校验 token 使用的签名算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method %v", token.Header["alg"])
		}

		// 返回密钥用于验证签名
		return secretKey, nil
	})

	if err != nil {
		log.Fatal("Error parsing token:", err)
	}

	// 验证 token 是否有效
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		fmt.Println("Token is valid")
		fmt.Println("Claims:", claims)
	} else {
		fmt.Println("Invalid token")
	}
}
  • jwt.Parse(tokenString, keyFunc) 用来解析 JWT,并验证其签名。keyFunc 是一个函数,用来返回签名验证时所需的密钥。
  • token.Claims.(jwt.MapClaims) 用于提取 JWT 中的声明部分(Payload)。
  • token.Valid 用来检查 JWT 是否有效。

5.2 检查 Token 是否过期

通常情况下,JWT 会包含 exp 声明,表示过期时间。你可以通过解析后的 claims 来检查 token 是否过期:

if exp, ok := claims["exp"].(float64); ok {
	if int64(exp) < time.Now().Unix() {
		fmt.Println("Token has expired")
	} else {
		fmt.Println("Token is valid")
	}
}

6. 自定义 Claims

除了标准的声明(如 sub, iat, exp 等),你可以自定义声明,以满足业务需求。

type CustomClaims struct {
	Username string `json:"username"`
	jwt.RegisteredClaims
}

func main() {
	// 创建一个新的 token
	claims := &CustomClaims{
		Username: "john_doe",
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer: "myapp",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	tokenString, err := token.SignedString(secretKey)
	if err != nil {
		log.Fatal("Failed to sign token:", err)
	}

	fmt.Println("Generated Custom Token:", tokenString)
}
  • CustomClaims 包含了自定义的字段(如 Username),同时嵌套了 jwt.RegisteredClaims,以支持标准声明。
  • jwt.NewWithClaims() 用于创建带有自定义声明的 JWT。

7. 总结

jwt-go 库提供了一个简单且功能强大的 API 来处理 JWT。你可以用它来:

  • 创建和签名 JWT。
  • 解析和验证 JWT。
  • 使用对称或非对称签名算法(如 HS256RS256)。
  • 自定义 JWT 的声明。
  • 处理 JWT 的过期时间和有效性验证。

jwt-go 是构建现代 Web 应用、API、微服务和分布式系统时,进行认证和授权的一个非常重要的工具。


标题:golang每日一库之jwt-go
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/02/10/1739164178198.html
联系:scotttu@163.com