Gin中间件开发与鉴权实践
1. 中间件执行流程
[客户端请求]↓
[Logger中间件] → 记录请求开始时间↓
[CORS中间件] → 处理跨域请求↓
[JWT鉴权] → 验证访问令牌↓
[RBAC鉴权] → 校验用户权限↓
[业务处理] → 核心业务逻辑↓
[Logger中间件] ← 记录响应耗时
2. JWT鉴权完整实现
2.1 生成JWT令牌
func GenerateToken(userID string, roles []string) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"userID": userID,"roles": roles,"exp": time.Now().Add(8 * time.Hour).Unix(),})return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
}
2.2 鉴权中间件
func JWTAuth() gin.HandlerFunc {return func(c *gin.Context) {tokenString := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")token, err := jwt.Parse(tokenString, 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(os.Getenv("JWT_SECRET")), nil})if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {c.Set("userID", claims["userID"])c.Set("roles", claims["roles"])c.Next()} else {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})}}
}
3. RBAC权限中间件
func RequireRole(role string) gin.HandlerFunc {return func(c *gin.Context) {roles, exists := c.Get("roles")if !exists {c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "access denied"})return}for _, r := range roles.([]string) {if r == role {c.Next()return}}c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})}
}
4. 跨域中间件配置
func CORSMiddleware() gin.HandlerFunc {return cors.New(cors.Config{AllowOrigins: []string{"https://prod.com", "http://localhost:3000"},AllowMethods: []string{"GET", "POST", "PUT", "PATCH"},AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},ExposeHeaders: []string{"Content-Length"},AllowCredentials: true,MaxAge: 12 * time.Hour,})
}
5. 中间件调试技巧
- 上下文数据追踪
// 在中间件中添加调试信息
c.Set("requestID", uuid.NewString())
log.Printf("[%s] %s %s", c.GetString("requestID"), c.Request.Method, c.Request.URL)
- 中间件执行顺序验证
router.Use(middleware.LatencyLogger(),middleware.CORSMiddleware(),middleware.JWTAuth(),
)
6. 单元测试方案
6.1 中间件测试示例
func TestJWTMiddleware(t *testing.T) {router := gin.New()router.Use(JWTAuth())router.GET("/test", func(c *gin.Context) {c.Status(http.StatusOK)})// 有效令牌测试t.Run("valid token", func(t *testing.T) {token, _ := GenerateToken("user123", []string{"admin"})w := httptest.NewRecorder()req, _ := http.NewRequest("GET", "/test", nil)req.Header.Set("Authorization", "Bearer "+token)router.ServeHTTP(w, req)assert.Equal(t, http.StatusOK, w.Code)})
}
6.2 测试覆盖率统计
# 生成测试覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
最佳实践
- 中间件链式调用示例:
router.Use(middleware.Recovery(),middleware.CORSMiddleware(),middleware.JWTAuth(),middleware.RequireRole("admin"),middleware.RequestLogger(),
)
- 敏感信息过滤:
// 在日志中间件中过滤敏感字段
if strings.Contains(c.Request.URL.Path, "/auth") {c.Writer = &responseWrapper{c.Writer, c}
}