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}
}