2010-04-05 21 views
260

Soy totalmente nuevo en la pila de ASP.NET MVC, y me preguntaba qué pasó con el objeto de página simple y el objeto Request ServerVariables?¿Cómo puedo obtener la dirección IP del cliente en ASP.NET MVC?

Básicamente, quiero extraer la dirección IP de la PC del cliente, pero no entiendo cómo la estructura MVC actual ha cambiado todo esto.

Por lo que puedo entender, most of the variable objects has been replaced by the HttpRequest variants.

¿Alguien quiere compartir algunos recursos? Realmente hay un montón de cosas para aprender en el mundo ASP.NET MVC. :)

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 puedo llamar a esta función desde la página del controlador?

+0

https://www.nuget.org/packages/XFF – efaruk

Respuesta

360

La respuesta simple es usar el HttpRequest.UserHostAddress property.

Ejemplo: Desde dentro de un Controlador de:

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 de ayuda:

using System.Web; 

namespace Mvc.Helpers 
{ 
    public static class HelperClass 
    { 
     public static string GetIPHelper() 
     { 
      string ip = HttpContext.Current.Request.UserHostAddress; 
      .. 
     } 
    } 
} 

PERO, si la petición ha sido transmitida por uno , o más, proxy servers luego la dirección IP devuelta por HttpRequest.UserHostAddress property será la dirección IP del último servidor proxy que Layed la solicitud.

Los servidores proxy PUEDEN utilizar el estándar de facto de colocar la dirección IP del cliente en el encabezado HTTP X-Forwarded-For. Además de que no hay garantía de que una solicitud tenga un encabezado X-Forwarded-For, tampoco hay garantía de que 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 la búsqueda de una colección. La propiedad Solicitud está disponible dentro de 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; 
} 
+0

Esta es una gran respuesta; Nunca he visto el encabezado X_Forwarded_For. Leí la página de la wiki sobre esto, pero realmente me interesaría por qué sería multivalor, o en qué lugares del mundo real lo ha visto. – LamonteCristo

+6

@ makerofthings7: Puede haber valores múltiples porque varios servidores proxy pueden estar reenviando a lo largo de la solicitud HTTP del cliente. Si los servidores proxy se comportan "bien" (a diferencia de los proxies intencionalmente anónimos o solo los mal programados), cada uno aplicará el IP de la anterior en el encabezado XFF. –

+9

¿Qué hace el método isPrivateIP? – eddiegroves

162

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 (La solicitud es una propiedad de la clase Controlador en MVC, no en la página).

Está funcionando ... pero tiene que publicar en un IIS real y no en uno virtual.

+0

¿Cómo puedo llamar esto desde el lado del controlador? – melaos

+0

Ver la actualización. Simplemente escriba Request.ServerVariables ["..."] etc – ovolko

+0

jajaja, hey que funciona, ¿qué pasa si quiero poner eso en un objeto de clase como el anterior? y ¿todavía necesito el objeto de la página? – melaos

19

En una clase que se podría llamar 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; 
} 

he utilizado esto en una aplicación de afeitar con excelentes resultados.

20

Tuve problemas para utilizar lo anterior, y necesitaba la dirección IP de un controlador. Usé lo siguiente al final:

System.Web.HttpContext.Current.Request.UserHostAddress 
+2

Desde el controlador todo lo que tenía que hacer era 'HttpContext.Request.UserHostAddress' –

+0

Gracias. Lo que necesitaba en una clase de ayuda no en un controlador o dentro de un contexto de visualización. Esta es una bonita respuesta universal. +1 – ppumkin

+0

@ppumkin deberías buscar declaraciones de "uso" ... – ganders

91

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í están algunas pruebas NUnit contra ese código (estoy usando burla de Rhino para burlarse del HttpRequestBase, que es el M < HttpRequestBase continuación > llamada):

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); 
    } 
} 
+2

Esto siempre devuelve la dirección IP del servidor que ejecuta mi aplicación. –

+0

¿No debería devolver 'publicForwardingIps.First()'? – andy250

+0

@Noah Supongo que esto no funcionará para las direcciones IPv6? – AidanO

2

Cómo dar cuenta de mi sitio estar detrás de un Amazon AWS Elastic Load Balancer (ELB):

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; 
    } 
} 
Cuestiones relacionadas