< 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
91%
Covered lines: 21
Uncovered lines: 2
Coverable lines: 23
Total lines: 75
Line coverage: 91.3%
Branch coverage
72%
Covered branches: 26
Total branches: 36
Branch coverage: 72.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_UserId()100%1414100%
get_Username()33.33%1212100%
get_Host()87.5%8890%
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
 816    public CurrentUserContext(IHttpContextAccessor httpContextAccessor)
 17    {
 818        _httpContextAccessor = httpContextAccessor;
 819    }
 20
 21    public long? UserId
 22    {
 23        get
 24        {
 325            var user = _httpContextAccessor.HttpContext?.User;
 326            var id = user?.FindFirstValue(ClaimTypes.NameIdentifier)
 327                     ?? user?.FindFirstValue("sub")
 328                     ?? user?.FindFirstValue("userId");
 29
 330            return long.TryParse(id, out var parsed) ? parsed : null;
 31        }
 32    }
 33
 34    public string? Username
 135        => _httpContextAccessor.HttpContext?.User?.Identity?.Name
 136           ?? _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
 37
 38    /// <summary>
 39    /// IP del cliente que realiza la acción.
 40    /// Si la app está detrás de proxy/ingress, usa X-Forwarded-For (primer IP).
 41    /// Caso contrario usa RemoteIpAddress.
 42    /// </summary>
 43    public string? Host
 44    {
 45        get
 46        {
 447            var http = _httpContextAccessor.HttpContext;
 548            if (http == null) return null;
 49
 50            // 1) Proxy (si existe). Tomar el primer valor.
 351            var xff = http.Request.Headers["X-Forwarded-For"].ToString();
 352            if (!string.IsNullOrWhiteSpace(xff))
 53            {
 154                var first = xff.Split(',')[0].Trim();
 155                if (IPAddress.TryParse(first, out var ipParsed))
 156                    return NormalizeIp(ipParsed);
 57
 58                // Si viene con puerto u otro formato, devolver lo más cercano
 059                return first;
 60            }
 61
 62            // 2) Conexión directa
 263            var remote = http.Connection.RemoteIpAddress;
 264            return remote != null ? NormalizeIp(remote) : null;
 65        }
 66    }
 67
 68    private static string NormalizeIp(IPAddress ip)
 69    {
 270        if (ip.IsIPv4MappedToIPv6)
 071            ip = ip.MapToIPv4();
 72
 273        return ip.ToString();
 74    }
 75}