package middleware import ( "aggios-app/backend/internal/config" "aggios-app/backend/internal/domain" "context" "log" "net/http" "strings" "github.com/golang-jwt/jwt/v5" ) // UnifiedAuthMiddleware valida JWT unificado e permite múltiplos tipos de usuários func UnifiedAuthMiddleware(cfg *config.Config, allowedTypes ...domain.UserType) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Extrair token do header Authorization authHeader := r.Header.Get("Authorization") if authHeader == "" { log.Printf("🚫 UnifiedAuth: Missing Authorization header") http.Error(w, "Unauthorized: Missing token", http.StatusUnauthorized) return } // Formato esperado: "Bearer " parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { log.Printf("🚫 UnifiedAuth: Invalid Authorization format") http.Error(w, "Unauthorized: Invalid token format", http.StatusUnauthorized) return } tokenString := parts[1] // Parsear e validar token token, err := jwt.ParseWithClaims(tokenString, &domain.UnifiedClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(cfg.JWT.Secret), nil }) if err != nil { log.Printf("🚫 UnifiedAuth: Token parse error: %v", err) http.Error(w, "Unauthorized: Invalid token", http.StatusUnauthorized) return } claims, ok := token.Claims.(*domain.UnifiedClaims) if !ok || !token.Valid { log.Printf("🚫 UnifiedAuth: Invalid token claims") http.Error(w, "Unauthorized: Invalid token", http.StatusUnauthorized) return } // Verificar se o tipo de usuário é permitido if len(allowedTypes) > 0 { allowed := false for _, allowedType := range allowedTypes { if claims.UserType == allowedType { allowed = true break } } if !allowed { log.Printf("🚫 UnifiedAuth: User type %s not allowed (allowed: %v)", claims.UserType, allowedTypes) http.Error(w, "Forbidden: Insufficient permissions", http.StatusForbidden) return } } // Adicionar informações ao contexto ctx := r.Context() ctx = context.WithValue(ctx, UserIDKey, claims.UserID) ctx = context.WithValue(ctx, TenantIDKey, claims.TenantID) ctx = context.WithValue(ctx, "email", claims.Email) ctx = context.WithValue(ctx, "user_type", string(claims.UserType)) ctx = context.WithValue(ctx, "role", claims.Role) // Para compatibilidade com handlers de portal que esperam CustomerIDKey if claims.UserType == domain.UserTypeCustomer { ctx = context.WithValue(ctx, CustomerIDKey, claims.UserID) } log.Printf("✅ UnifiedAuth: Authenticated user_id=%s, type=%s, role=%s, tenant=%s", claims.UserID, claims.UserType, claims.Role, claims.TenantID) next.ServeHTTP(w, r.WithContext(ctx)) }) } } // RequireAgencyUser middleware que permite apenas usuários de agência (admin, colaborador) func RequireAgencyUser(cfg *config.Config) func(http.Handler) http.Handler { return UnifiedAuthMiddleware(cfg, domain.UserTypeAgency) } // RequireCustomer middleware que permite apenas clientes func RequireCustomer(cfg *config.Config) func(http.Handler) http.Handler { return UnifiedAuthMiddleware(cfg, domain.UserTypeCustomer) } // RequireAnyAuthenticated middleware que permite qualquer usuário autenticado func RequireAnyAuthenticated(cfg *config.Config) func(http.Handler) http.Handler { return UnifiedAuthMiddleware(cfg) // Sem filtro de tipo }