如何在ASP.NET MVC中获取客户端的IP地址?

我完全不熟悉ASP.NET MVC堆栈,我想知道简单的Page对象和Request ServerVariables对象发生了什么?

基本上,我想要拔出客户端PC的IP地址,但我不明白现在的MVC结构如何改变了这一切。

据我所知, 大部分variables对象已经被HttpRequest变体所取代 。

有人关心分享一些资源? ASP.NET MVC世界中真的有很多东西需要学习。 🙂

例如,我有这个当前函数的静态类。 如何使用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; } 

我怎样从控制器页面调用这个函数?

简单的答案是使用HttpRequest.UserHostAddress属性 。

示例:从控制器内部:

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

例如:从一个辅助类中:

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

但是,如果请求已被一个或多个代理服务器传递,那么HttpRequest.UserHostAddress属性返回的IP地址将是中继请求的最后一个代理服务器的IP地址。

代理服务器可以使用将客户端的IP地址放在X-Forwarded-For HTTP标头中的事实标准。 除了不保证请求具有X-Forwarded-For头部,也不能保证X-Forwarded-For没有被SPOOFED


原始答复

 Request.UserHostAddress 

上面的代码提供了客户端的IP地址,而不需要查找一个集合。 请求属性在控制器(或视图)中可用。 因此,而不是传递一个Page类到你的函数,你可以通过一个请求对象得到相同的结果:

 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"]应该直接在视图中或在控制器操作方法体中(Request是MVC中Controller类的属性,而不是页面)。

它正在工作..但你必须在真正的IIS上发布而不是虚拟的。

这里的很多代码是非常有帮助的,但是为了我的目的,我把它清理干净了,并添加了一些testing。 以下是我最终的结果:

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

下面是一些针对该代码的NUnittesting(我使用Rhino Mocks来模拟HttpRequestBase,这是下面的M <HttpRequestBase>调用):

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

我在使用上述时遇到了麻烦,而且我需要一个控制器的IP地址。 我最后使用了以下内容:

 System.Web.HttpContext.Current.Request.UserHostAddress 

在课堂上,你可以这样称呼它:

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

我在一个剃刀应用程序中使用这个很好的结果。

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