go jwt
Go 生态中最流行的 JWT 库是 `github.com/golang-jwt/jwt/v5`(原 `dgrijalva/jwt-go` 的社区维护分支,更安全可靠)。c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"})c.JSON(http.StatusUnauthorized, gin.H{"error": "
我来为你详细介绍在 Go 语言中使用 JWT 的实践方案。
Go 语言 JWT 库推荐
Go 生态中最流行的 JWT 库是 `github.com/golang-jwt/jwt/v5`(原 `dgrijalva/jwt-go` 的社区维护分支,更安全可靠)。
快速开始
1. 安装依赖
```bash
go get github.com/golang-jwt/jwt/v5
```
2. 基础使用示例
生成 Token(登录时)
```go
package main
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
// 定义密钥(生产环境应从环境变量读取)
var jwtSecret = []byte("your-256-bit-secret")
// 自定义 Claims 结构
type UserClaims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims // 内嵌标准声明
}
// 生成 JWT
func GenerateToken(userID uint, username string) (string, error) {
claims := UserClaims{
UserID: userID,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 24小时过期
IssuedAt: jwt.NewNumericDate(time.Now()),
Subject: "user_token",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
```
解析和验证 Token(中间件中)
```go
// 解析 JWT
func ParseToken(tokenString string) (*UserClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
// 验证签名算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrSignatureInvalid
}
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
return claims, nil
}
return nil, jwt.ErrInvalidKey
}
```
Gin 框架集成示例
这是实际项目中最常见的使用场景:
```go
package main
import (
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key")
// JWT 中间件
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证头"})
c.Abort()
return
}
// 提取 Bearer token
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
c.JSON(http.StatusUnauthorized, gin.H{"error": "认证头格式错误"})
c.Abort()
return
}
// 解析 token
claims, err := ParseToken(parts[1])
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的token"})
c.Abort()
return
}
// 将用户信息存入上下文
c.Set("userID", claims.UserID)
c.Set("username", claims.Username)
c.Next()
}
}
func main() {
r := gin.Default()
// 公开路由
r.POST("/login", loginHandler)
// 需要认证的路由组
api := r.Group("/api")
api.Use(JWTAuthMiddleware())
{
api.GET("/profile", profileHandler)
api.POST("/logout", logoutHandler)
}
r.Run(":8080")
}
// 登录处理
func loginHandler(c *gin.Context) {
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 验证用户名密码(示例,实际应查数据库)
if req.Username != "admin" || req.Password != "123456" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "认证失败"})
return
}
// 生成 token
token, err := GenerateToken(1, req.Username)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"token": token,
"type": "Bearer",
})
}
// 获取个人信息(需要认证)
func profileHandler(c *gin.Context) {
userID, _ := c.Get("userID")
username, _ := c.Get("username")
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": username,
})
}
```
高级特性
使用 RSA 非对称加密(更安全的微服务场景)
```go
// 生成 Token(使用私钥)
func GenerateTokenWithRSA(userID uint, privateKey *rsa.PrivateKey) (string, error) {
claims := jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
return token.SignedString(privateKey)
}
// 验证 Token(使用公钥)
func ParseTokenWithRSA(tokenString string, publicKey *rsa.PublicKey) (*jwt.Token, error) {
return jwt.Parse(tokenString, 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
})
}
```
Token 刷新机制
```go
// RefreshToken 在 token 即将过期时生成新 token
func RefreshToken(tokenString string) (string, error) {
claims, err := ParseToken(tokenString)
if err != nil {
return "", err
}
// 检查是否需要刷新(例如剩余时间小于30分钟)
if time.Until(claims.ExpiresAt.Time) > 30*time.Minute {
return "", errors.New("token 尚未需要刷新")
}
// 生成新 token
return GenerateToken(claims.UserID, claims.Username)
}
```
目录结构建议
```
project/
├── internal/
│ ├── middleware/
│ │ └── jwt.go # JWT 中间件
│ └── utils/
│ └── jwt.go # JWT 工具函数
├── pkg/
│ └── config/
│ └── config.go # 密钥配置
└── cmd/
└── server/
└── main.go
```
安全最佳实践
实践 说明
密钥管理 使用环境变量或密钥管理服务(KMS),不要硬编码
算法选择 优先使用 `HS256` 或 `RS256`,避免 `none` 算法
过期时间 设置合理的过期时间(建议 15分钟-2小时)
HTTPS 传输 生产环境必须使用 HTTPS
Token 存储 前端存储在 `httpOnly` Cookie 或内存中,避免 LocalStorage XSS 风险
需要了解更具体的场景实现(如 Redis 存储黑名单实现登出、多设备登录控制等)吗?
更多推荐

所有评论(0)