How can I get the client's IP address in ASP.NET MVC?
我对ASP.NET MVC堆栈完全陌生,我想知道简单的页面对象和请求服务器变量对象发生了什么?
基本上,我想拔出客户机PC的IP地址,但我无法理解当前的MVC结构是如何改变这一切的。
据我所知,大多数变量对象都被httpRequest变量替换了。
有人愿意分享资源吗?在ASP.NET MVC的世界里,有很多东西需要学习。:)
例如,我有一个带有这个当前函数的静态类。如何使用ASP.NET MVC获得相同的结果?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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属性。
示例:从控制器内部:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System; using System.Web.Mvc; namespace Mvc.Controllers { public class HomeController : ClientController { public ActionResult Index() { string ip = Request.UserHostAddress; ... } } } |
示例:从助手类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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没有被欺骗。
原始答案
1 | Request.UserHostAddress |
上面的代码提供了客户机的IP地址,而不需要查找集合。请求属性在控制器(或视图)中可用。因此,您可以传递一个请求对象来获得相同的结果,而不是将一个页面类传递给您的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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; } |
它在工作……但是你必须在真实的IIS上发布,而不是虚拟的。
这里的很多代码都非常有用,但是为了我的目的我清理了它并添加了一些测试。我的结论是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 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; } } |
下面是一些针对该代码的nunit测试(我使用Rhino Mocks模拟httpRequestBase,它是下面的m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 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地址。最后我使用了以下内容:
1 | System.Web.HttpContext.Current.Request.UserHostAddress |
在一个类中,您可以这样称呼它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } |
我在Razor应用程序中使用了这个,效果很好。
我如何解释我的网站背后的亚马逊AWS弹性负载平衡器(ELB):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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; } } |