Perfecto. A continuación, te dejo una solución profesional y reutilizable para .NET 8: un middleware que detecta si el cliente proviene de una red local y, si no, marca el request como “requiere 2FA” o “requiere CAPTCHA”.
También se puede usar en un filtro de acción, si prefieres aplicar la lógica solo en controladores específicos.
OBJETIVO
- Detectar si la IP del cliente está en una red de confianza.
- Marcar el request como requiere seguridad adicional.
- Usar esto en endpoints REST API para tomar decisiones (ej. pedir 2FA o CAPTCHA).
Middleware global (ideal para APIs públicas)
1. Instala dependencia para validar rangos CIDR:
dotnet add package IPNetwork2
2. Crea el middleware
// Middlewares/TrustedNetworkMiddleware.cs
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using NetTools;
public class TrustedNetworkMiddleware
{
private readonly RequestDelegate _next;
private readonly List<IPAddressRange> _trustedRanges;
public TrustedNetworkMiddleware(RequestDelegate next, IEnumerable<string> trustedCidrs)
{
_next = next;
_trustedRanges = trustedCidrs.Select(IPAddressRange.Parse).ToList();
}
public async Task InvokeAsync(HttpContext context)
{
var ip = ObtenerIpCliente(context);
if (ip is not null && EsIpConfiable(ip))
{
context.Items["EsRedConfiable"] = true;
}
else
{
context.Items["EsRedConfiable"] = false;
}
await _next(context);
}
private static IPAddress? ObtenerIpCliente(HttpContext context)
{
var forwarded = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (!string.IsNullOrEmpty(forwarded) && IPAddress.TryParse(forwarded, out var ipF))
return ipF;
return context.Connection.RemoteIpAddress;
}
private bool EsIpConfiable(IPAddress ip)
{
return _trustedRanges.Any(r => r.Contains(ip));
}
}
3. Extensión para Program.cs
public static class TrustedNetworkMiddlewareExtensions
{
public static IApplicationBuilder UseTrustedNetworkDetection(this IApplicationBuilder app, IEnumerable<string> trustedCidrs)
{
return app.UseMiddleware<TrustedNetworkMiddleware>(trustedCidrs);
}
}
4. En Program.cs (antes de MapControllers)
var app = builder.Build();
var redesConfiables = new[]
{
"192.168.0.0/16",
"10.0.0.0/8",
"172.16.0.0/12",
"TU_RED_CORPORATIVA_PUBLICA/24"
};
app.UseTrustedNetworkDetection(redesConfiables);
5. Uso en tus controladores
[HttpPost("login")]
public IActionResult Login([FromBody] LoginRequest request)
{
var esRedConfiable = HttpContext.Items["EsRedConfiable"] as bool? ?? false;
if (esRedConfiable)
{
// Saltar CAPTCHA o 2FA
return Ok(new { token = GenerarJwt() });
}
// Requiere paso adicional
return Ok(new { requiere2fa = true, requiereCaptcha = true });
}
Alternativa: Filtro de acción para ciertos endpoints
Úsalo si solo quieres aplicar esta lógica en controladores específicos:
public class SoloRedConfiableAttribute : ActionFilterAttribute
{
private readonly List<IPAddressRange> _trustedRanges;
public SoloRedConfiableAttribute(string[] trustedCidrs)
{
_trustedRanges = trustedCidrs.Select(IPAddressRange.Parse).ToList();
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var ip = context.HttpContext.Connection.RemoteIpAddress;
var esConfiable = ip != null && _trustedRanges.Any(r => r.Contains(ip));
if (!esConfiable)
{
context.Result = new ForbidResult(); // o Unauthorized, según el caso
}
}
}
Uso:
[HttpPost("solo-red-local")]
[ServiceFilter(typeof(SoloRedConfiableAttribute), Arguments = new object[] { new[] { "192.168.0.0/16" } })]
public IActionResult SoloRedLocal()
{
return Ok("Estás en red confiable");
}