From bdb952c0e55880ed6c3fb637eb2f5cc45c06cbd6 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Mon, 26 Jan 2026 09:15:08 -0300 Subject: [PATCH] Fix tenant-aware login resolution --- Controllers/AuthController.cs | 39 +++++++++++++++++++++++++++++------ Dtos/LoginRequest.cs | 2 +- Services/TenantMiddleware.cs | 5 +++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index a4d2dc9..c5b3269 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -72,16 +72,34 @@ public class AuthController : ControllerBase [HttpPost("login")] public async Task Login(LoginRequest req) { - // ✅ normaliza e evita null var email = (req.Email ?? "").Trim().ToLowerInvariant(); var password = req.Password ?? ""; var normalizedEmail = _userManager.NormalizeEmail(email); - // ✅ SOLUÇÃO A: ignora filtros globais (multi-tenant / HasQueryFilter) - // e pega 1 usuário (pra você logar logo). - var user = await _userManager.Users - .IgnoreQueryFilters() - .FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail); + var tenantId = ResolveTenantId(req); + ApplicationUser? user; + + if (tenantId == null) + { + var users = await _userManager.Users + .IgnoreQueryFilters() + .Where(u => u.NormalizedEmail == normalizedEmail) + .ToListAsync(); + + if (users.Count == 0) + return Unauthorized("Credenciais inválidas."); + + if (users.Count > 1) + return BadRequest("Informe o tenant para realizar o login."); + + user = users[0]; + } + else + { + user = await _userManager.Users + .IgnoreQueryFilters() + .FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail && u.TenantId == tenantId); + } if (user == null) return Unauthorized("Credenciais inválidas."); @@ -97,6 +115,15 @@ public class AuthController : ControllerBase return Ok(new AuthResponse(token)); } + private Guid? ResolveTenantId(LoginRequest req) + { + if (req.TenantId.HasValue) + return req.TenantId.Value; + + var headerValue = Request.Headers["X-Tenant-Id"].FirstOrDefault(); + return Guid.TryParse(headerValue, out var parsed) ? parsed : null; + } + private async Task GenerateJwtAsync(ApplicationUser user) { var key = _config["Jwt:Key"]!; diff --git a/Dtos/LoginRequest.cs b/Dtos/LoginRequest.cs index cd9cb75..1c48a61 100644 --- a/Dtos/LoginRequest.cs +++ b/Dtos/LoginRequest.cs @@ -1,3 +1,3 @@ namespace line_gestao_api.Dtos; -public record LoginRequest(string Email, string Password); +public record LoginRequest(string Email, string Password, Guid? TenantId = null); diff --git a/Services/TenantMiddleware.cs b/Services/TenantMiddleware.cs index 1806992..f978eed 100644 --- a/Services/TenantMiddleware.cs +++ b/Services/TenantMiddleware.cs @@ -16,11 +16,16 @@ public class TenantMiddleware Guid? tenantId = null; var claim = context.User.FindFirst("tenantId")?.Value ?? context.User.FindFirst("tenant")?.Value; + var headerValue = context.Request.Headers["X-Tenant-Id"].FirstOrDefault(); if (Guid.TryParse(claim, out var parsed)) { tenantId = parsed; } + else if (Guid.TryParse(headerValue, out var headerTenant)) + { + tenantId = headerTenant; + } tenantProvider.SetTenantId(tenantId);