Come posso ottenere l’indirizzo IP del client in ASP.NET MVC?

Sono totalmente nuovo allo stack ASP.NET MVC e mi chiedevo cosa fosse successo all’object Page semplice e all’object Request ServerVariables?

Fondamentalmente, voglio estrarre l’indirizzo IP del PC client, ma non riesco a capire come l’attuale struttura MVC abbia cambiato tutto questo.

Per quanto posso capire, la maggior parte degli oggetti variabili è stata sostituita dalle varianti HttpRequest .

Qualcuno vuole condividere alcune risorse? C’è davvero un mare di cose da imparare nel mondo ASP.NET MVC. 🙂

Ad esempio, ho una class statica con questa funzione corrente. Come ottengo lo stesso risultato 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; } 

E come posso chiamare questa funzione dalla pagina del controller?

La semplice risposta è usare la proprietà HttpRequest.UserHostAddress .

Esempio: da un controller:

 using System; using System.Web.Mvc; namespace Mvc.Controllers { public class HomeController : ClientController { public ActionResult Index() { string ip = Request.UserHostAddress; ... } } } 

Esempio: da una class helper:

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

MA, se la richiesta è stata inoltrata da uno o più server proxy , l’indirizzo IP restituito dalla proprietà HttpRequest.UserHostAddress sarà l’indirizzo IP dell’ultimo server proxy che ha inoltrato la richiesta.

I server proxy POSSONO utilizzare lo standard de facto di inserire l’indirizzo IP del client nell’intestazione HTTP X-Forwarded-For . A parte ciò, non vi è alcuna garanzia che una richiesta abbia un’intestazione X-Forwarded-For, non è inoltre garantito che X-Forwarded-For non sia stato SPOOFED .


Risposta originale

 Request.UserHostAddress 

Il codice precedente fornisce l’indirizzo IP del client senza ricorrere alla ricerca di una raccolta. La proprietà Richiesta è disponibile all’interno di Controller (o Viste). Pertanto, anziché passare una class Page alla tua funzione, puoi passare un object Request per ottenere lo stesso risultato:

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

Request.ServerVariables["REMOTE_ADDR"] dovrebbe funzionare – direttamente in una vista o nel corpo del metodo di azione del controllore (Request è una proprietà della class Controller in MVC, non Page).

Funziona .. ma devi pubblicare su un IIS reale non virtuale.

Molto del codice qui è stato molto utile, ma l’ho ripulito per i miei scopi e ho aggiunto alcuni test. Ecco cosa ho finito 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; } } 

E qui ci sono alcuni test NUnit contro quel codice (sto usando Rhino Mocks per deridere HttpRequestBase, che è la chiamata M qui sotto):

 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 MalformsdIpAddress = "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(); } [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 MalformsdUserHostAddress_Returns_DefaultIpAddress() { // Arrange _httpRequest.Stub(x => x.UserHostAddress).Return(MalformsdIpAddress); _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null); // Act var ip = RequestHelpers.GetClientIpAddress(_httpRequest); // Assert ip.ShouldEqual(DefaultIpAddress); } [Test] public void MalformsdXForwardedFor_Returns_DefaultIpAddress() { // Arrange _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MalformsdIpAddress); // 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); } } 

Ho avuto problemi nell’usare quanto sopra, e avevo bisogno dell’indirizzo IP da un controller. Alla fine ho usato quanto segue:

 System.Web.HttpContext.Current.Request.UserHostAddress 

In una class potresti chiamarla così:

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

L’ho usato in un’app per razor con ottimi risultati.

In che modo conto che il mio sito si trova dietro un Elastic Load Balancer (ELB) Amazon AWS :

 public class GetPublicIp { ///  /// account for possbility of ELB sheilding the public IP address ///  ///  public static string Execute() { try { Console.WriteLine(string.Join("|", new List { 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; } }