golang,go,博客,开源,编程
在 Gin 中实现 JWT(JSON Web Token)认证 中间件,主要目的是通过解析请求中的 JWT token,验证其合法性,进而判断请求是否被授权访问某些受保护的资源。JWT 是一种紧凑、安全的 URL-safe 的方式,用于表示通过 JSON 对象传递的声明。JWT 可以用于身份验证和信息交换。
我们可以编写一个自定义中间件来实现 JWT 认证。常见的实现流程如下:
Authorization
字段。Bearer
token 并解析。以下是基于 Gin 的 JWT 认证中间件示例:
package main
import (
"fmt"
"github.com/dgrijalva/jwt-go" // 你可以使用其他库,dgrijalva/jwt-go 是常用的 Go JWT 库
"github.com/gin-gonic/gin"
"net/http"
"strings"
"time"
)
var jwtSecret = []byte("your-secret-key") // 用于签名和验证 JWT 的密钥
// JWT 中间件
func JWTMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从 Authorization header 中获取 token
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Authorization header is missing",
})
c.Abort()
return
}
// Bearer token 格式:Authorization: Bearer <token>
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Invalid Authorization header format",
})
c.Abort()
return
}
// 获取 JWT token
tokenString := parts[1]
// 解析 JWT token
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 jwtSecret, nil
})
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Invalid token",
})
c.Abort()
return
}
// 如果验证通过,可以将 token 中的信息放到 context 中
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// 将用户信息(如用户 ID)保存到上下文中,供后续的路由使用
c.Set("user_id", claims["user_id"])
c.Set("username", claims["username"])
}
// 继续处理请求
c.Next()
}
}
// 模拟生成 JWT token
func GenerateJWT(userID string, username string) (string, error) {
// 创建一个声明(Claims)
claims := jwt.MapClaims{}
claims["user_id"] = userID
claims["username"] = username
claims["exp"] = time.Now().Add(time.Hour * 24).Unix() // 设置过期时间
// 创建 token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 使用 secret 密钥签名并生成 token 字符串
return token.SignedString(jwtSecret)
}
func main() {
// 创建 Gin 实例
r := gin.Default()
// 公共路由:无需验证的接口
r.GET("/login", func(c *gin.Context) {
// 模拟用户登录,生成 JWT
token, err := GenerateJWT("12345", "user_name")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": "Failed to generate token",
})
return
}
c.JSON(http.StatusOK, gin.H{
"token": token,
})
})
// 受保护路由:需要 JWT 认证的接口
protected := r.Group("/protected")
protected.Use(JWTMiddleware()) // 使用 JWT 中间件进行认证
protected.GET("/data", func(c *gin.Context) {
userID, _ := c.Get("user_id")
username, _ := c.Get("username")
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": username,
"message": "This is protected data",
})
})
// 启动 Gin 服务
r.Run(":8080")
}
GenerateJWT
函数:
jwt.MapClaims
来创建一个包含 user_id
、username
和 exp
(过期时间)等信息的声明。jwt.NewWithClaims
来创建一个新的 JWT,并通过密钥 jwtSecret
对其进行签名。JWTMiddleware
中间件:
Authorization
字段提取 Bearer token。jwt.Parse
解析 token,并验证其签名和有效性。user_id
和 username
等信息存储到 Gin 的上下文中(c.Set
),供后续路由使用。/login
路由:
/protected/data
路由:
启动服务后,访问 http://localhost:8080/login
会生成一个 JWT。
curl http://localhost:8080/login
返回一个 JSON 响应,包含生成的 token:
{
"token": "your-jwt-token"
}
使用返回的 token 访问 /protected/data
路由:
curl -H "Authorization: Bearer your-jwt-token" http://localhost:8080/protected/data
如果 token 验证通过,返回:
{
"user_id": "12345",
"username": "user_name",
"message": "This is protected data"
}
如果没有提供有效的 token,则返回 401 错误:
curl http://localhost:8080/protected/data
返回:
{
"message": "Authorization header is missing"
}
jwtSecret
在生产环境中应该保密,可以使用环境变量或配置文件来管理密钥。exp
),过期后需要重新登录或刷新 token。SigningMethodHS256
),如果你需要使用其他算法(例如 RSA),可以在 jwt.NewWithClaims
中选择不同的算法。通过在 Gin 中实现 JWT 认证中间件,可以保护你的 API 接口,确保只有经过身份验证的用户才能访问受保护的资源。JWT 提供了简便、无状态的身份认证方式,适合现代 Web 应用和微服务架构。