asp.net-mvc - route - tag helper asp net core 2
¿Cómo puedo obtener la dirección IP del cliente en ASP.NET MVC? (6)
Soy totalmente nuevo en la pila MVC de ASP.NET, y me preguntaba qué sucedió con el objeto Page simple y el objeto Request ServerVariables
Básicamente, quiero extraer la dirección IP de la PC cliente, pero no entiendo cómo la estructura actual de MVC ha cambiado todo esto.
Hasta donde puedo entender, la mayoría de los objetos variables han sido reemplazados por las variantes HttpRequest .
¿A alguien le interesa compartir algunos recursos? Realmente hay un mar de cosas que aprender en el mundo MVC de ASP.NET. :)
Por ejemplo, tengo una clase estática con esta función actual. ¿Cómo obtengo el mismo resultado usando ASP.NET MVC?
public static int getCountry(Page page)
{
return getCountryFromIP(getIPAddress(page));
}
public static string getIPAddress(Page page)
{
string szRemoteAddr = page.Request.ServerVariables["REMOTE_ADDR"];
string szXForwardedFor = page.Request.ServerVariables["X_FORWARDED_FOR"];
string szIP = "";
if (szXForwardedFor == null)
{
szIP = szRemoteAddr;
}
else
{
szIP = szXForwardedFor;
if (szIP.IndexOf(",") > 0)
{
string [] arIPs = szIP.Split('','');
foreach (string item in arIPs)
{
if (!isPrivateIP(item))
{
return item;
}
}
}
}
return szIP;
}
¿Y cómo llamo a esta función desde la página del controlador?
Cómo considero que mi sitio está detrás de un equilibrador de carga elástica (ELB) de Amazon AWS :
public class GetPublicIp {
/// <summary>
/// account for possbility of ELB sheilding the public IP address
/// </summary>
/// <returns></returns>
public static string Execute() {
try {
Console.WriteLine(string.Join("|", new List<object> {
HttpContext.Current.Request.UserHostAddress,
HttpContext.Current.Request.Headers["X-Forwarded-For"],
HttpContext.Current.Request.Headers["REMOTE_ADDR"]
})
);
var ip = HttpContext.Current.Request.UserHostAddress;
if (HttpContext.Current.Request.Headers["X-Forwarded-For"] != null) {
ip = HttpContext.Current.Request.Headers["X-Forwarded-For"];
Console.WriteLine(ip + "|X-Forwarded-For");
}
else if (HttpContext.Current.Request.Headers["REMOTE_ADDR"] != null) {
ip = HttpContext.Current.Request.Headers["REMOTE_ADDR"];
Console.WriteLine(ip + "|REMOTE_ADDR");
}
return ip;
}
catch (Exception ex) {
Console.Error.WriteLine(ex.Message);
}
return null;
}
}
En una clase puedes llamarlo así:
public static string GetIPAddress(HttpRequestBase request)
{
string ip;
try
{
ip = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!string.IsNullOrEmpty(ip))
{
if (ip.IndexOf(",") > 0)
{
string[] ipRange = ip.Split('','');
int le = ipRange.Length - 1;
ip = ipRange[le];
}
} else
{
ip = request.UserHostAddress;
}
} catch { ip = null; }
return ip;
}
Utilicé esto en una aplicación de afeitar con grandes resultados.
La respuesta simple es usar la propiedad HttpRequest.UserHostAddress .
Ejemplo: desde dentro de un controlador:
using System;
using System.Web.Mvc;
namespace Mvc.Controllers
{
public class HomeController : ClientController
{
public ActionResult Index()
{
string ip = Request.UserHostAddress;
...
}
}
}
Ejemplo: desde dentro de una clase auxiliar:
using System.Web;
namespace Mvc.Helpers
{
public static class HelperClass
{
public static string GetIPHelper()
{
string ip = HttpContext.Current.Request.UserHostAddress;
..
}
}
}
PERO, si la solicitud ha sido aprobada por uno o más servidores proxy , la dirección IP devuelta por la propiedad HttpRequest.UserHostAddress será la dirección IP del último servidor proxy que retransmitió la solicitud.
Los servidores proxy PUEDEN usar el estándar de facto para colocar la dirección IP del cliente en el encabezado HTTP X-Forwarded-For . Aparte de que no hay garantía de que una solicitud tenga un encabezado X-Forwarded-For, tampoco hay garantía de que el X-Forwarded-For no haya sido SPOOFED .
Respuesta original
Request.UserHostAddress
El código anterior proporciona la dirección IP del cliente sin tener que recurrir a buscar una colección. La propiedad de solicitud está disponible dentro de los controladores (o vistas). Por lo tanto, en lugar de pasar una clase de página a su función, puede pasar un objeto de solicitud para obtener el mismo resultado:
public static string getIPAddress(HttpRequestBase request)
{
string szRemoteAddr = request.UserHostAddress;
string szXForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];
string szIP = "";
if (szXForwardedFor == null)
{
szIP = szRemoteAddr;
}
else
{
szIP = szXForwardedFor;
if (szIP.IndexOf(",") > 0)
{
string [] arIPs = szIP.Split('','');
foreach (string item in arIPs)
{
if (!isPrivateIP(item))
{
return item;
}
}
}
}
return szIP;
}
Mucho del código aquí fue muy útil, pero lo limpié para mis propósitos y agregué algunas pruebas. Esto es lo que terminé con:
using System;
using System.Linq;
using System.Net;
using System.Web;
public class RequestHelpers
{
public static string GetClientIpAddress(HttpRequestBase request)
{
try
{
var userHostAddress = request.UserHostAddress;
// Attempt to parse. If it fails, we catch below and return "0.0.0.0"
// Could use TryParse instead, but I wanted to catch all exceptions
IPAddress.Parse(userHostAddress);
var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(xForwardedFor))
return userHostAddress;
// Get a list of public ip addresses in the X_FORWARDED_FOR variable
var publicForwardingIps = xForwardedFor.Split('','').Where(ip => !IsPrivateIpAddress(ip)).ToList();
// If we found any, return the last one, otherwise return the user host address
return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress;
}
catch (Exception)
{
// Always return all zeroes for any failure (my calling code expects it)
return "0.0.0.0";
}
}
private static bool IsPrivateIpAddress(string ipAddress)
{
// http://en.wikipedia.org/wiki/Private_network
// Private IP Addresses are:
// 24-bit block: 10.0.0.0 through 10.255.255.255
// 20-bit block: 172.16.0.0 through 172.31.255.255
// 16-bit block: 192.168.0.0 through 192.168.255.255
// Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address)
var ip = IPAddress.Parse(ipAddress);
var octets = ip.GetAddressBytes();
var is24BitBlock = octets[0] == 10;
if (is24BitBlock) return true; // Return to prevent further processing
var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31;
if (is20BitBlock) return true; // Return to prevent further processing
var is16BitBlock = octets[0] == 192 && octets[1] == 168;
if (is16BitBlock) return true; // Return to prevent further processing
var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254;
return isLinkLocalAddress;
}
}
Y aquí hay algunas pruebas NUnit contra ese código (estoy usando Rhino Mocks para simular el HttpRequestBase, que es la llamada M <HttpRequestBase> a continuación):
using System.Web;
using NUnit.Framework;
using Rhino.Mocks;
using Should;
[TestFixture]
public class HelpersTests : TestBase
{
HttpRequestBase _httpRequest;
private const string XForwardedFor = "X_FORWARDED_FOR";
private const string MalformedIpAddress = "MALFORMED";
private const string DefaultIpAddress = "0.0.0.0";
private const string GoogleIpAddress = "74.125.224.224";
private const string MicrosoftIpAddress = "65.55.58.201";
private const string Private24Bit = "10.0.0.0";
private const string Private20Bit = "172.16.0.0";
private const string Private16Bit = "192.168.0.0";
private const string PrivateLinkLocal = "169.254.0.0";
[SetUp]
public void Setup()
{
_httpRequest = M<HttpRequestBase>();
}
[TearDown]
public void Teardown()
{
_httpRequest = null;
}
[Test]
public void PublicIpAndNullXForwardedFor_Returns_CorrectIp()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(GoogleIpAddress);
}
[Test]
public void PublicIpAndEmptyXForwardedFor_Returns_CorrectIp()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(string.Empty);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(GoogleIpAddress);
}
[Test]
public void MalformedUserHostAddress_Returns_DefaultIpAddress()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(MalformedIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(DefaultIpAddress);
}
[Test]
public void MalformedXForwardedFor_Returns_DefaultIpAddress()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MalformedIpAddress);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(DefaultIpAddress);
}
[Test]
public void SingleValidPublicXForwardedFor_Returns_XForwardedFor()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MicrosoftIpAddress);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(MicrosoftIpAddress);
}
[Test]
public void MultipleValidPublicXForwardedFor_Returns_LastXForwardedFor()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(GoogleIpAddress + "," + MicrosoftIpAddress);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(MicrosoftIpAddress);
}
[Test]
public void SinglePrivateXForwardedFor_Returns_UserHostAddress()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(Private24Bit);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(GoogleIpAddress);
}
[Test]
public void MultiplePrivateXForwardedFor_Returns_UserHostAddress()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
const string privateIpList = Private24Bit + "," + Private20Bit + "," + Private16Bit + "," + PrivateLinkLocal;
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(GoogleIpAddress);
}
[Test]
public void MultiplePublicXForwardedForWithPrivateLast_Returns_LastPublic()
{
// Arrange
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
const string privateIpList = Private24Bit + "," + Private20Bit + "," + MicrosoftIpAddress + "," + PrivateLinkLocal;
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);
// Act
var ip = RequestHelpers.GetClientIpAddress(_httpRequest);
// Assert
ip.ShouldEqual(MicrosoftIpAddress);
}
}
Tuve problemas para usar lo anterior y necesitaba la dirección IP de un controlador. Utilicé lo siguiente al final:
System.Web.HttpContext.Current.Request.UserHostAddress
Request.ServerVariables["REMOTE_ADDR"]
debería funcionar, ya sea directamente en una vista o en el cuerpo del método de acción del controlador (Request es una propiedad de la clase Controller en MVC, no en Page).
Está funcionando ... pero hay que publicar en un IIS real, no en el virtual.