using System.Security.Claims; using Aegis.Application.Abstractions; using Microsoft.Extensions.Caching.Memory; namespace Aegis.API.Auth; public class UserResolutionMiddleware(RequestDelegate next, IMemoryCache cache) { // TTL do cache (ajuste como quiser) private static readonly TimeSpan CacheTtl = TimeSpan.FromHours(1); public async Task InvokeAsync(HttpContext ctx, IUserIdentityRepository repo, CancellationToken ct) { // Só roda para requests autenticadas if (ctx.User?.Identity?.IsAuthenticated == true) { var sub = ctx.User.FindFirstValue("sub"); var iss = ctx.User.FindFirstValue("iss"); if (!string.IsNullOrWhiteSpace(sub) && !string.IsNullOrWhiteSpace(iss)) { var cacheKey = $"aegis_uid|{iss}|{sub}"; if (!cache.TryGetValue(cacheKey, out string? userIdValue)) { var displayName = ctx.User.FindFirstValue("name") ?? ctx.User.FindFirstValue("preferred_username"); var email = ctx.User.FindFirstValue("email"); var userId = await repo.GetOrCreateAsync(sub, iss, displayName, email, ct); userIdValue = userId.Value; cache.Set( cacheKey, userIdValue, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = CacheTtl, SlidingExpiration = TimeSpan.FromMinutes(15) }); } // Injeta claim aegis_uid se não existir if (ctx.User.FindFirst("aegis_uid") is null && userIdValue is not null) { if (ctx.User.Identity is ClaimsIdentity identity) identity.AddClaim(new Claim("aegis_uid", userIdValue)); } } } await next(ctx); } }