< Summary

Information
Class: FAU.API.Services.CurrentUserContext
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Services/CurrentUserContext.cs
Line coverage
82%
Covered lines: 23
Uncovered lines: 5
Coverable lines: 28
Total lines: 92
Line coverage: 82.1%
Branch coverage
70%
Covered branches: 28
Total branches: 40
Branch coverage: 70%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
SetUserId(...)100%210%
get_UserId()93.75%1616100%
get_Username()33.33%1212100%
get_Host()80%101090.9%
NormalizeIp(...)50%2266.66%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Services/CurrentUserContext.cs

#LineLine coverage
 1using System.Net;
 2using System.Security.Claims;
 3using FAU.Logica.Services;
 4using Microsoft.AspNetCore.Http;
 5
 6namespace FAU.API.Services;
 7
 8/// <summary>
 9/// Implementaci�n HTTP de ICurrentUserContext.
 10/// Extrae datos desde claims (JWT) y del request actual.
 11/// </summary>
 12public sealed class CurrentUserContext : ICurrentUserContext
 13{
 14    private readonly IHttpContextAccessor _httpContextAccessor;
 15
 16    // Overrides para background tasks o contextos sin HttpContext (ej. CLI, hangfire)
 17    private long? _overrideUserId;
 18    private string? _overrideHost;
 19
 820    public CurrentUserContext(IHttpContextAccessor httpContextAccessor)
 21    {
 822        _httpContextAccessor = httpContextAccessor;
 823    }
 24
 25    /// <summary>
 26    /// Permite setear el usuario manualmente (ej. background task que no tiene HttpContext).
 27    /// </summary>
 28    public void SetUserId(long? userId, string? host = null)
 29    {
 030        _overrideUserId = userId;
 031        _overrideHost = host;
 032    }
 33
 34    public long? UserId
 35    {
 36        get
 37        {
 338            if (_overrideUserId.HasValue) return _overrideUserId.Value;
 39
 340            var user = _httpContextAccessor.HttpContext?.User;
 341            var id = user?.FindFirstValue(ClaimTypes.NameIdentifier)
 342                     ?? user?.FindFirstValue("sub")
 343                     ?? user?.FindFirstValue("userId");
 44
 345            return long.TryParse(id, out var parsed) ? parsed : null;
 46        }
 47    }
 48
 49    public string? Username
 150        => _httpContextAccessor.HttpContext?.User?.Identity?.Name
 151           ?? _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
 52
 53    /// <summary>
 54    /// IP del cliente que realiza la acci�n.
 55    /// Si la app est� detr�s de proxy/ingress, usa X-Forwarded-For (primer IP).
 56    /// Caso contrario usa RemoteIpAddress.
 57    /// </summary>
 58    public string? Host
 59    {
 60        get
 61        {
 462            if (_overrideHost != null) return _overrideHost;
 63
 464            var http = _httpContextAccessor.HttpContext;
 565            if (http == null) return null;
 66
 67            // 1) Proxy (si existe). Tomar el primer valor.
 368            var xff = http.Request.Headers["X-Forwarded-For"].ToString();
 369            if (!string.IsNullOrWhiteSpace(xff))
 70            {
 171                var first = xff.Split(',')[0].Trim();
 172                if (IPAddress.TryParse(first, out var ipParsed))
 173                    return NormalizeIp(ipParsed);
 74
 75                // Si viene con puerto u otro formato, devolver lo m�s cercano
 076                return first;
 77            }
 78
 79            // 2) Conexi�n directa
 280            var remote = http.Connection.RemoteIpAddress;
 281            return remote != null ? NormalizeIp(remote) : null;
 82        }
 83    }
 84
 85    private static string NormalizeIp(IPAddress ip)
 86    {
 287        if (ip.IsIPv4MappedToIPv6)
 088            ip = ip.MapToIPv4();
 89
 290        return ip.ToString();
 91    }
 92}