package middleware import ( "net/http" "patbin/config" "strings" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) type Claims struct { UserID uint `json:"user_id"` Username string `json:"username"` jwt.RegisteredClaims } // AuthMiddleware validates JWT token and sets user info in context func AuthMiddleware(cfg *config.Config) gin.HandlerFunc { return func(c *gin.Context) { // Try to get token from cookie first tokenString, err := c.Cookie(cfg.CookieName) if err != nil { // Try Authorization header authHeader := c.GetHeader("Authorization") if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") { tokenString = strings.TrimPrefix(authHeader, "Bearer ") } } if tokenString == "" { c.Next() return } // Parse and validate token claims := &Claims{} token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return []byte(cfg.JWTSecret), nil }) if err != nil || !token.Valid { c.Next() return } // Set user info in context c.Set("user_id", claims.UserID) c.Set("username", claims.Username) c.Set("authenticated", true) c.Next() } } // RequireAuth ensures user is authenticated func RequireAuth() gin.HandlerFunc { return func(c *gin.Context) { authenticated, exists := c.Get("authenticated") if !exists || !authenticated.(bool) { // Check if API request or web request if strings.HasPrefix(c.Request.URL.Path, "/api/") { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication required"}) } else { c.Redirect(http.StatusFound, "/login") } c.Abort() return } c.Next() } } // GetUserID returns the authenticated user ID from context func GetUserID(c *gin.Context) (uint, bool) { userID, exists := c.Get("user_id") if !exists { return 0, false } return userID.(uint), true } // GetUsername returns the authenticated username from context func GetUsername(c *gin.Context) (string, bool) { username, exists := c.Get("username") if !exists { return "", false } return username.(string), true }