package middleware import ( "errors" "net/http" "strings" "time" "git.beifan.cn/trace-system/backend-go/config" "git.beifan.cn/trace-system/backend-go/database" "git.beifan.cn/trace-system/backend-go/models" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) // JWTAuthMiddleware JWT 认证中间件 func JWTAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "缺少授权头部", }) return } parts := strings.SplitN(authHeader, " ", 2) if !(len(parts) == 2 && parts[0] == "Bearer") { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "授权头部格式错误", }) return } tokenStr := parts[1] // 解析 JWT token token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("不支持的签名方法") } cfg := config.GetAppConfig() return []byte(cfg.JWT.Secret), nil }) if err != nil || !token.Valid { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "无效的访问令牌", }) return } // 验证 claims if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { // 检查过期时间 if exp, ok := claims["exp"].(float64); ok { if time.Now().Unix() > int64(exp) { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "令牌已过期", }) return } } // 获取用户 ID if userId, ok := claims["userId"].(float64); ok { // 验证用户是否存在 var user models.User result := database.DB.First(&user, uint(userId)) if result.Error != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "用户不存在", }) return } // 将用户信息存储到上下文 c.Set("user", user) } else { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "令牌无效", }) return } } c.Next() } } // AdminMiddleware 管理员权限中间件 func AdminMiddleware() gin.HandlerFunc { return func(c *gin.Context) { user, exists := c.Get("user") if !exists { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "message": "未认证", }) return } userModel := user.(models.User) if userModel.Role != "admin" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{ "message": "无权限访问此资源", }) return } c.Next() } }