jwt-go
是一个用于处理 JSON Web Tokens (JWT) 的 Go 语言库。它支持多种算法,如 HS256、RS256 等。以下是如何在 Go 语言项目中使用 jwt-go
的基本步骤:
安装 jwt-go
首先,需要安装 jwt-go
包。可以使用以下命令:
go get -u github.com/dgrijalva/jwt-go
生成 JWT
生成 JWT 时,需要定义一个 Token
结构,并使用相应的密钥进行签名。
package main
import (
"fmt"
"time"
"github.com/dgrijalva/jwt-go"
)
func main() {
// 定义JWT的签发者和接收者
issuer := "example.com"
audience := "api.example.com"
// 定义JWT的过期时间
expirationTime := time.Now().Add(24 * time.Hour)
// 创建一个JWT的Token对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"iss": issuer, // 签发者
"aud": audience, // 接收者
"iat": time.Now().Unix(), // 发布时间
"nbf": time.Now().Unix(), // 在此之前不可用
"exp": expirationTime.Unix(), // 过期时间
"custom": "data", // 自定义数据
})
// 使用密钥进行签名
key := []byte("secret")
signedToken, err := token.SignedString(key)
if err != nil {
fmt.Println("Token signing error:", err)
return
}
fmt.Println("Signed Token:", signedToken)
}
验证 JWT
验证 JWT 时,需要使用相同的密钥和算法来验证签名。
package main
import (
"fmt"
"time"
"github.com/dgrijalva/jwt-go"
)
func main() {
token := "你的JWT字符串" // 从上一步生成的JWT字符串
// 解析JWT字符串
tokenObj, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
// 确保算法是HS256
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// 返回用于验证签名的密钥
return []byte("secret"), nil
})
if err != nil {
fmt.Println("Token parsing error:", err)
return
}
// 检查Token是否有效
if claims, ok := tokenObj.Claims.(jwt.MapClaims); ok && tokenObj.Valid {
fmt.Println("Token is valid!")
fmt.Println("Issuer:", claims["iss"])
fmt.Println("Audience:", claims["aud"])
fmt.Println("Expiration Time:", time.Unix(int64(claims["exp"].(float64)), 0))
} else {
fmt.Println("Token is not valid!")
}
}
使用 RS256 算法
如果你需要使用 RS256 算法,需要生成 RSA 密钥对,并使用私钥签名,公钥验证。
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"github.com/dgrijalva/jwt-go"
)
func main() {
// 生成RSA密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("Error generating RSA key:", err)
return
}
// 将私钥写入文件
privateKeyPem := x509.MarshalPKCS1PrivateKey(privateKey)
err = os.WriteFile("private.pem", privateKeyPem, 0600)
if err != nil {
fmt.Println("Error writing private key to file:", err)
return
}
// 使用私钥生成JWT
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "example.com",
"aud": "api.example.com",
"iat": time.Now().Unix(),
"exp": time.Now().Add(24 * time.Hour).Unix(),
})
signer, err := jwt.NewRSASigner(privateKey)
if err != nil {
fmt.Println("Error creating RSA signer:", err)
return
}
signedToken, err := token.SignedString(signer)
if err != nil {
fmt.Println("Error signing token:", err)
return
}
fmt.Println("Signed Token:", signedToken)
// 读取公钥
publicKeyBytes, err := os.ReadFile("public.pem")
if err != nil {
fmt.Println("Error reading public key file:", err)
return
}
publicKey, err := jwt.ParseRSAPublicKeyFromPEM(publicKeyBytes)
if err != nil {
fmt.Println("Error parsing public key:", err)
return
}
// 验证JWT
tokenObj, err := jwt.Parse(signedToken, func(token *jwt.Token) (interface{}, error) {
return publicKey, nil
})
if err != nil {
fmt.Println("Error parsing token:", err)
return
}
if claims, ok := tokenObj.Claims.(jwt.MapClaims); ok && tokenObj.Valid {
fmt.Println("Token is valid!")
fmt.Println("Issuer:", claims["iss"])
fmt.Println("Audience:", claims["aud"])
} else {
fmt.Println("Token is not valid!")
}
}
在实际应用中,你可能需要根据具体需求调整 JWT 的内容和验证逻辑。jwt-go
提供了灵活的接口来满足不同的需求。