// Package middleware 提供 Gin 中间件:跨域、JWT 鉴权、超管校验 package middleware import ( "strings" "github.com/gin-gonic/gin" "nl-game-api-gin/internal/database" "nl-game-api-gin/internal/model" "nl-game-api-gin/pkg/jwtutil" "nl-game-api-gin/pkg/resp" ) // CORS 跨域中间件:开发时前端(5173)与后端(8080)端口不同,需要放行跨域请求 func CORS() gin.HandlerFunc { return func(c *gin.Context) { origin := c.GetHeader("Origin") if origin != "" { c.Header("Access-Control-Allow-Origin", origin) c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization") } // 预检请求直接返回 204 if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } // Auth JWT 鉴权中间件:从 Authorization: Bearer xxx 中解析用户身份 // 校验通过后将 user_id 与 role 写入上下文供后续处理函数使用 func Auth() gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") token := strings.TrimPrefix(authHeader, "Bearer ") if token == "" || token == authHeader { resp.Unauthorized(c, "请先登录") return } claims, err := jwtutil.Parse(token) if err != nil { resp.Unauthorized(c, "登录已过期,请重新登录") return } // 查库校验账号仍然有效:否则封禁/删除的用户在 Token 过期前仍可操作全部接口 var user model.User if err := database.DB.Select("status").First(&user, claims.UserID).Error; err != nil { resp.Unauthorized(c, "账号不存在,请重新登录") return } if user.Status == model.UserStatusBanned { resp.Forbidden(c, "账号已被禁用") return } // 身份信息写入请求上下文 c.Set("user_id", claims.UserID) c.Set("role", claims.Role) c.Next() } } // AdminOnly 超管校验中间件:需在 Auth 之后使用,非超管直接拒绝 func AdminOnly() gin.HandlerFunc { return func(c *gin.Context) { if c.GetInt("role") != model.RoleAdmin { resp.Forbidden(c, "仅超级管理员可操作") return } c.Next() } } // UID 从上下文取当前登录用户ID的快捷方法 func UID(c *gin.Context) int { return c.GetInt("user_id") }