golang安全简单高效的JSON Web Tokens生成与验证插件库jwt的使用
Golang安全简单高效的JSON Web Tokens生成与验证插件库jwt的使用
简介
这是一个用于Go语言的JSON Web Token(JWT)实现库,遵循RFC 7519标准。该库设计简洁、API清晰、性能优化且线程安全。
特性
- 简单易用的API
- 干净且经过测试的代码
- 针对速度进行了优化
- 线程安全
- 无依赖
- 支持所有常见算法:
- HMAC (HS)
- RSA (RS)
- RSA-PSS (PS)
- ECDSA (ES)
- EdDSA (EdDSA)
- 或自定义算法
安装
Go版本要求1.17+
go get github.com/cristalhq/jwt/v5
使用示例
生成JWT Token
// 创建一个签名器(这里使用HMAC示例)
key := []byte(`secret`)
signer, err := jwt.NewSignerHS(jwt.HS256, key)
if err != nil {
panic(err)
}
// 创建声明(可以创建自定义声明)
claims := &jwt.RegisteredClaims{
Audience: []string{"admin"},
ID: "random-unique-string",
}
// 创建Builder
builder := jwt.NewBuilder(signer)
// 构建Token
token, err := builder.Build(claims)
if err != nil {
panic(err)
}
// 获取Token字符串
tokenString := token.String()
fmt.Println("Generated token:", tokenString)
解析和验证JWT Token
// 创建一个验证器(这里使用HMAC示例)
key := []byte(`secret`)
verifier, err := jwt.NewVerifierHS(jwt.HS256, key)
if err != nil {
panic(err)
}
// 解析并验证Token
tokenBytes := []byte(tokenString)
newToken, err := jwt.Parse(tokenBytes, verifier)
if err != nil {
panic(err)
}
// 或者只验证签名
err = verifier.Verify(newToken)
if err != nil {
panic(err)
}
// 获取注册声明
var newClaims jwt.RegisteredClaims
err = json.Unmarshal(newToken.Claims(), &newClaims)
if err != nil {
panic(err)
}
// 或者直接解析声明
err = jwt.ParseClaims(tokenBytes, verifier, &newClaims)
if err != nil {
panic(err)
}
// 验证声明
isForAdmin := newClaims.IsForAudience("admin")
isValid := newClaims.IsValidAt(time.Now())
fmt.Printf("Is for admin: %v, Is valid: %v\n", isForAdmin, isValid)
自定义声明
// 自定义声明结构
type UserClaims struct {
jwt.RegisteredClaims
Username string `json:"username"`
IsAdmin bool `json:"isAdmin"`
}
// 使用自定义声明
userClaims := &UserClaims{
RegisteredClaims: jwt.RegisteredClaims{
ID: "user-123",
},
Username: "john_doe",
IsAdmin: true,
}
// 构建Token
token, err := builder.Build(userClaims)
if err != nil {
panic(err)
}
// 解析时使用自定义声明
var parsedClaims UserClaims
err = jwt.ParseClaims(token.Bytes(), verifier, &parsedClaims)
if err != nil {
panic(err)
}
fmt.Printf("User: %s, Admin: %v\n", parsedClaims.Username, parsedClaims.IsAdmin)
注意事项
- 确保使用足够强度的密钥
- 合理设置Token的过期时间
- 不要在不安全的通道传输Token
- 验证Token时检查所有必要的声明
这个库提供了简单而强大的JWT功能,适合大多数Go应用程序的安全需求。
更多关于golang安全简单高效的JSON Web Tokens生成与验证插件库jwt的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang安全简单高效的JSON Web Tokens生成与验证插件库jwt的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang JWT 库使用指南
JSON Web Tokens (JWT) 是一种流行的身份验证和授权机制,在Go语言中有多个优秀的JWT实现库。下面我将介绍最常用的 github.com/golang-jwt/jwt
库的使用方法。
安装
首先安装库:
go get github.com/golang-jwt/jwt/v5
基本使用
1. 生成JWT Token
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
// 自定义Claims结构体
type MyCustomClaims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims
}
func main() {
// 定义秘钥
mySigningKey := []byte("your-256-bit-secret")
// 创建Claims
claims := MyCustomClaims{
12345,
"john_doe",
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 过期时间24小时
IssuedAt: jwt.NewNumericDate(time.Now()), // 签发时间
NotBefore: jwt.NewNumericDate(time.Now()), // 生效时间
Issuer: "test", // 签发者
Subject: "somebody", // 主题
ID: "1", // 唯一ID
Audience: []string{"somebody_else"}, // 受众
},
}
// 创建Token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 签名并获取完整Token
ss, err := token.SignedString(mySigningKey)
if err != nil {
fmt.Printf("Error creating token: %v\n", err)
return
}
fmt.Printf("Token: %v\n", ss)
}
2. 验证JWT Token
func verifyToken(tokenString string) (*MyCustomClaims, error) {
// 解析Token
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// 验证签名方法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// 返回秘钥
return []byte("your-256-bit-secret"), nil
})
if err != nil {
return nil, err
}
// 验证Claims
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
高级用法
1. 使用RSA非对称加密
// 生成RSA Token
func generateRSAToken() (string, error) {
// 读取私钥
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(`-----BEGIN RSA PRIVATE KEY-----
... 私钥内容 ...
-----END RSA PRIVATE KEY-----`))
if err != nil {
return "", err
}
claims := jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
Issuer: "auth-service",
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
return token.SignedString(privateKey)
}
// 验证RSA Token
func verifyRSAToken(tokenString string) (*jwt.RegisteredClaims, error) {
// 读取公钥
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(`-----BEGIN PUBLIC KEY-----
... 公钥内容 ...
-----END PUBLIC KEY-----`))
if err != nil {
return nil, err
}
token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return publicKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*jwt.RegisteredClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
2. 刷新Token
func refreshToken(oldToken string) (string, error) {
// 先验证旧Token
claims, err := verifyToken(oldToken)
if err != nil {
return "", err
}
// 检查是否在可刷新时间范围内
if time.Until(claims.ExpiresAt.Time) > 30*time.Minute {
return "", fmt.Errorf("token is not expired yet")
}
// 创建新Token
newClaims := MyCustomClaims{
UserID: claims.UserID,
Username: claims.Username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: claims.Issuer,
},
}
newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
return newToken.SignedString([]byte("your-256-bit-secret"))
}
安全建议
- 秘钥管理:不要将秘钥硬编码在代码中,使用环境变量或秘钥管理服务
- 过期时间:设置合理的过期时间,通常访问令牌1小时,刷新令牌7-30天
- 算法选择:优先使用RS256而非HS256,避免对称加密的安全风险
- 敏感数据:不要在JWT中存储敏感信息,JWT可以被解码查看
- HTTPS:始终通过HTTPS传输JWT
错误处理
func handleTokenError(err error) {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
fmt.Println("That's not even a token")
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
fmt.Println("Token is expired")
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
fmt.Println("Token is not active yet")
} else {
fmt.Println("Couldn't handle this token:", err)
}
} else {
fmt.Println("Couldn't parse token:", err)
}
}
以上就是Go语言中使用JWT的基本方法,这个库简单易用且功能强大,适合大多数应用场景。