using Microsoft.AspNetCore.Mvc; using OnlyOneAccessTemplate.Services; namespace OnlyOneAccessTemplate.Controllers { [Route("api/modules")] public class DynamicProxyController : ControllerBase { private readonly IModuleService _moduleService; private readonly HttpClient _httpClient; private readonly IRateLimitService _rateLimitService; private readonly ILogger _logger; public DynamicProxyController( IModuleService moduleService, HttpClient httpClient, IRateLimitService rateLimitService, ILogger logger) { _moduleService = moduleService; _httpClient = httpClient; _rateLimitService = rateLimitService; _logger = logger; } [HttpPost("{moduleId}/{action}")] [HttpGet("{moduleId}/{action}")] [HttpPut("{moduleId}/{action}")] [HttpDelete("{moduleId}/{action}")] public async Task ProxyRequest(string moduleId, string action) { try { // Buscar configuração do módulo var module = await _moduleService.GetModuleConfigAsync(moduleId); if (module == null || !module.IsActive) { return NotFound(new { success = false, message = "Módulo não encontrado ou inativo" }); } // Rate limiting var clientIP = GetClientIP(); await _rateLimitService.RecordRequestAsync(clientIP); if (await _rateLimitService.ShouldShowCaptchaAsync(clientIP)) { return StatusCode(429, new { success = false, message = "Rate limit exceeded", requiresCaptcha = true }); } // Verificar se o endpoint existe no mapeamento if (!module.ProxyMappings.ContainsKey(action)) { return NotFound(new { success = false, message = $"Ação '{action}' não disponível para este módulo" }); } var targetUrl = module.ProxyMappings[action]; // Preparar requisição var requestMessage = new HttpRequestMessage( new HttpMethod(Request.Method), targetUrl + Request.QueryString); // Copiar headers necessários foreach (var header in module.Headers) { requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); } // Copiar corpo da requisição se necessário if (Request.ContentLength > 0) { requestMessage.Content = new StreamContent(Request.Body); if (Request.ContentType != null) { requestMessage.Content.Headers.TryAddWithoutValidation("Content-Type", Request.ContentType); } } _logger.LogInformation("Proxying {Method} request to {ModuleId}.{Action} -> {TargetUrl}", Request.Method, moduleId, action, targetUrl); // Fazer requisição var response = await _httpClient.SendAsync(requestMessage); var responseContent = await response.Content.ReadAsStringAsync(); // Retornar resposta Response.StatusCode = (int)response.StatusCode; if (response.Content.Headers.ContentType?.MediaType != null) { Response.ContentType = response.Content.Headers.ContentType.MediaType; } return Content(responseContent); } catch (Exception ex) { _logger.LogError(ex, "Erro no proxy para {ModuleId}.{Action}", moduleId, action); return StatusCode(500, new { success = false, message = "Erro interno do servidor" }); } } private string GetClientIP() { return HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown"; } } }