我们有请求。UserHostAddress在ASP. ASP. ASP中获取IP地址。NET,但这通常是用户的ISP的IP地址,而不是用户点击链接的机器IP地址。如何获取真实IP地址?
例如,在Stack Overflow用户配置文件中,它是:“上次帐户活动:4小时前从86.123.127.8开始”,但我的机器IP地址有点不同。Stack Overflow如何获得这个地址?
在一些web系统中,出于某些目的有一个IP地址检查。例如,对于某个IP地址,每24小时用户只能点击5次下载链接吗?这个IP地址应该是唯一的,而不是针对一个拥有大量客户端或互联网用户的ISP。
我听懂了吗?
到目前为止,所有的响应都考虑了非标准化但非常常见的X-Forwarded-For报头。有一个标准化的转发头,它有点难以解析。一些例子如下:
Forwarded: for="_gazonk"
Forwarded: For="[2001:db8:cafe::17]:4711"
Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43
Forwarded: for=192.0.2.43, for=198.51.100.17
我已经编写了一个类,在确定客户端的IP地址时考虑这两个头。
using System;
using System.Web;
namespace Util
{
public static class IP
{
public static string GetIPAddress()
{
return GetIPAddress(new HttpRequestWrapper(HttpContext.Current.Request));
}
internal static string GetIPAddress(HttpRequestBase request)
{
// handle standardized 'Forwarded' header
string forwarded = request.Headers["Forwarded"];
if (!String.IsNullOrEmpty(forwarded))
{
foreach (string segment in forwarded.Split(',')[0].Split(';'))
{
string[] pair = segment.Trim().Split('=');
if (pair.Length == 2 && pair[0].Equals("for", StringComparison.OrdinalIgnoreCase))
{
string ip = pair[1].Trim('"');
// IPv6 addresses are always enclosed in square brackets
int left = ip.IndexOf('['), right = ip.IndexOf(']');
if (left == 0 && right > 0)
{
return ip.Substring(1, right - 1);
}
// strip port of IPv4 addresses
int colon = ip.IndexOf(':');
if (colon != -1)
{
return ip.Substring(0, colon);
}
// this will return IPv4, "unknown", and obfuscated addresses
return ip;
}
}
}
// handle non-standardized 'X-Forwarded-For' header
string xForwardedFor = request.Headers["X-Forwarded-For"];
if (!String.IsNullOrEmpty(xForwardedFor))
{
return xForwardedFor.Split(',')[0];
}
return request.UserHostAddress;
}
}
}
下面是我用来验证我的解决方案的一些单元测试:
using System.Collections.Specialized;
using System.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UtilTests
{
[TestClass]
public class IPTests
{
[TestMethod]
public void TestForwardedObfuscated()
{
var request = new HttpRequestMock("for=\"_gazonk\"");
Assert.AreEqual("_gazonk", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv6()
{
var request = new HttpRequestMock("For=\"[2001:db8:cafe::17]:4711\"");
Assert.AreEqual("2001:db8:cafe::17", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv4()
{
var request = new HttpRequestMock("for=192.0.2.60;proto=http;by=203.0.113.43");
Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv4WithPort()
{
var request = new HttpRequestMock("for=192.0.2.60:443;proto=http;by=203.0.113.43");
Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedMultiple()
{
var request = new HttpRequestMock("for=192.0.2.43, for=198.51.100.17");
Assert.AreEqual("192.0.2.43", Util.IP.GetIPAddress(request));
}
}
public class HttpRequestMock : HttpRequestBase
{
private NameValueCollection headers = new NameValueCollection();
public HttpRequestMock(string forwarded)
{
headers["Forwarded"] = forwarded;
}
public override NameValueCollection Headers
{
get { return this.headers; }
}
}
}