package middleware import ( "fmt" "net/http" "strings" "bugulma/backend/internal/service" "github.com/gin-gonic/gin" ) func AuthMiddleware(authService *service.AuthService) gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"}) c.Abort() return } tokenString := strings.TrimPrefix(authHeader, "Bearer ") if tokenString == authHeader { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization format"}) c.Abort() return } user, err := authService.ValidateToken(c.Request.Context(), tokenString) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) c.Abort() return } // Set user information in context c.Set("user_id", user.ID) c.Set("user_email", user.Email) c.Set("user_role", string(user.Role)) // Debug: Log the role being set (only in development) if gin.Mode() == gin.DebugMode { fmt.Printf("[AuthMiddleware] Setting user_role=%s for user_id=%s\n", string(user.Role), user.ID) } c.Next() } } func RequireRole(role string) gin.HandlerFunc { return func(c *gin.Context) { // Debug: Log all context keys (only in development) if gin.Mode() == gin.DebugMode { fmt.Printf("[RequireRole] Checking for role=%s, path=%s\n", role, c.Request.URL.Path) // Try to get all context values for debugging if userID, exists := c.Get("user_id"); exists { fmt.Printf("[RequireRole] Found user_id=%v\n", userID) } if userEmail, exists := c.Get("user_email"); exists { fmt.Printf("[RequireRole] Found user_email=%v\n", userEmail) } } userRole, exists := c.Get("user_role") if !exists { // Debug: List all available keys in context if gin.Mode() == gin.DebugMode { fmt.Printf("[RequireRole] user_role not found. Available keys in context:\n") // Note: Gin doesn't provide a direct way to list all keys, but we can check common ones } c.JSON(http.StatusForbidden, gin.H{ "error": "No role found - authentication middleware may not be applied", "required_role": role, "path": c.Request.URL.Path, }) c.Abort() return } // Convert to string for comparison - handle both string and interface{} types var userRoleStr string switch v := userRole.(type) { case string: userRoleStr = v default: userRoleStr = fmt.Sprintf("%v", v) } // Trim whitespace and compare (case-sensitive) userRoleStr = strings.TrimSpace(userRoleStr) if userRoleStr != role { c.JSON(http.StatusForbidden, gin.H{ "error": "Insufficient permissions", "required_role": role, "user_role": userRoleStr, "debug": map[string]interface{}{ "user_role_type": fmt.Sprintf("%T", userRole), "user_role_raw": userRole, "user_role_string": userRoleStr, "required_role": role, "match": userRoleStr == role, }, }) c.Abort() return } c.Next() } }