首页 文章

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

提问于
浏览
348

我们有 Request.UserHostAddress 来获取ASP.NET中的IP地址,但这通常是用户_121668的IP地址,而不是用户的机器IP地址,例如单击链接 . 我怎样才能获得真实的IP地址?

例如,在Stack Overflow用户配置文件中它是: "Last account activity: 4 hours ago from 86.123.127.8" ,但我的机器IP地址有点不同 . Stack Overflow如何获得此地址?

在某些Web系统中,出于某些目的进行IP地址检查 . 例如,使用某个IP地址,用户每24小时只能点击下载链接5次?此IP地址应该是唯一的,不适用于拥有大量客户端或Internet用户的ISP .

我理解得好吗?

16 回答

  • 15

    您可以使用:

    System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.GetValue(0).ToString();
    
  • 21

    用这个

    Dns.GetHostEntry(Dns.GetHostName())
    
  • 21

    您可以做的是存储用户的路由器IP以及转发的IP,并尝试使用IP [外部公共和内部私有]使其可靠 . 但是在几天后,客户端可能会从路由器分配新的内部IP,但它会更可靠 .

  • -7

    Try:

    using System.Net;
    
    public static string GetIpAddress()  // Get IP Address
    {
        string ip = "";     
        IPHostEntry ipEntry = Dns.GetHostEntry(GetCompCode());
        IPAddress[] addr = ipEntry.AddressList;
        ip = addr[2].ToString();
        return ip;
    }
    public static string GetCompCode()  // Get Computer Name
    {   
        string strHostName = "";
        strHostName = Dns.GetHostName();
        return strHostName;
    }
    
  • 9

    UPDATE: 感谢Bruno Lopes . 如果可能有多个ip地址,则需要使用此方法:

    private string GetUserIP()
        {
            string ipList = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    
            if (!string.IsNullOrEmpty(ipList))
            {
                return ipList.Split(',')[0];
            }
    
            return Request.ServerVariables["REMOTE_ADDR"];
        }
    
  • 130

    正如其他人所说,你不能做你所要求的 . 如果你描述了你试图解决的问题,也许有人可以提供帮助?例如 . 您是否尝试唯一标识您的用户?您是否可以使用cookie或会话ID而不是IP地址?

    Edit 您在服务器上看到的地址不应该是't be the ISP'的地址,正如您所说的那样,这将是一个巨大的范围 . 宽带上的家庭用户的地址将是其路由器上的地址,因此房屋内的每个设备都将在外部显示相同,但路由器使用NAT来确保流量正确地路由到每个设备 . 对于从办公室环境访问的用户,所有用户的地址可能相同 . 使用IP地址进行身份验证的网站存在使其出错的风险 - 您提供的示例很好,而且经常会失败 . 例如,我的办公室位于英国,突破点(我在互联网上的地方)位于我们主要IT设施所在的另一个国家,所以从我的办公室来看,我的IP地址似乎不在英国 . 出于这个原因,我无法访问仅限英国的网络内容,例如BBC iPlayer . 在任何时候,我公司的数百人甚至数千人似乎都是从同一个IP地址访问网络的 .

    在编写服务器代码时,您永远无法确定您看到的IP地址是指的是什么 . 有些用户喜欢这种方式 . 有些人故意使用代理或VPN来进一步混淆你 .

    当您说您的机器地址与StackOverflow上显示的IP地址不同时,您如何找到您的机器地址?如果您只是在本地使用 ipconfig 或类似的东西,我会期望它与我上面概述的原因不同 . 如果你想仔细检查外面世界的想法,请看whatismyipaddress.com/ .

    这个Wikipedia link on NAT将为您提供一些背景知识 .

  • -3

    通常,您会想知道访问您网站的人的IP地址 . 虽然ASP.NET有几种方法可以做到这一点,但我们看到的最佳方法之一是使用ServerVariables集合的“HTTP_X_FORWARDED_FOR” .

    这就是为什么......

    有时您的访问者位于代理服务器或路由器后面,标准 Request.UserHostAddress 仅捕获代理服务器或路由器的IP地址 . 在这种情况下,用户的IP地址将存储在服务器变量("HTTP_X_FORWARDED_FOR")中 .

    所以我们要做的是首先检查"HTTP_X_FORWARDED_FOR",如果它是空的,那么我们只需返回 ServerVariables("REMOTE_ADDR") .

    虽然这种方法并非万无一失,但它可以带来更好的结果 . 下面是VB.NET中的ASP.NET代码,取自James Crowley's blog post "Gotcha: HTTP_X_FORWARDED_FOR returns multiple IP addresses"

    C#

    protected string GetIPAddress()
    {
        System.Web.HttpContext context = System.Web.HttpContext.Current; 
        string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    
        if (!string.IsNullOrEmpty(ipAddress))
        {
            string[] addresses = ipAddress.Split(',');
            if (addresses.Length != 0)
            {
                return addresses[0];
            }
        }
    
        return context.Request.ServerVariables["REMOTE_ADDR"];
    }
    

    VB.NET

    Public Shared Function GetIPAddress() As String
        Dim context As System.Web.HttpContext = System.Web.HttpContext.Current
        Dim sIPAddress As String = context.Request.ServerVariables("HTTP_X_FORWARDED_FOR")
        If String.IsNullOrEmpty(sIPAddress) Then
            Return context.Request.ServerVariables("REMOTE_ADDR")
        Else
            Dim ipArray As String() = sIPAddress.Split(New [Char]() {","c})
            Return ipArray(0)
        End If
    End Function
    
  • 8

    在ashx文件中使用

    public string getIP(HttpContext c)
    {
        string ips = c.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
        if (!string.IsNullOrEmpty(ips))
        {
            return ips.Split(',')[0];
        }
        return c.Request.ServerVariables["REMOTE_ADDR"];
    }
    
  • 7

    如果是c#看到这种方式,很简单

    string clientIp = (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? 
                       Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim();
    
  • 3

    IP地址是“七层堆栈”中网络层的一部分 . 网络层可以对IP地址执行任何操作 . 这就是代理服务器,NAT,中继等等 .

    Application层不应以任何方式依赖于IP地址 . 特别地,IP地址并不意味着除了网络连接的一端的标识符之外的任何其他标识符 . 一旦连接关闭,您应该期望(同一用户的)IP地址发生变化 .

  • 23
    string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;
    
  • 398

    到目前为止,所有响应都考虑了非标准化但非常常见的 Headers . 有一个标准化的Forwarded Headers ,解析起来有点困难 . 一些例子如下:

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

    如果您使用的是CloudFlare,则可以尝试以下扩展方法:

    public static class IPhelper
    {
        public static string GetIPAddress(this HttpRequest Request)
        {
            if (Request.Headers["CF-CONNECTING-IP"] != null) return Request.Headers["CF-CONNECTING-IP"].ToString();
    
            if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null) return Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
    
            return Request.UserHostAddress;
        }
    }
    

    然后

    string IPAddress = Request.GetIPAddress();
    
  • 70

    结合@Tony@mangokun的答案,我创建了以下扩展方法:

    public static class RequestExtensions
    {
        public static string GetIPAddress(this HttpRequest Request)
        {
            if (Request.Headers["CF-CONNECTING-IP"] != null) return Request.Headers["CF-CONNECTING-IP"].ToString();
    
            if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
            {
                string ipAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    
                if (!string.IsNullOrEmpty(ipAddress))
                {
                    string[] addresses = ipAddress.Split(',');
                    if (addresses.Length != 0)
                    {
                        return addresses[0];
                    }
                }
            }
    
            return Request.UserHostAddress;
        }
    }
    
  • 14

    你还认为用户的IP地址是什么?如果你想要网络适配器的IP地址,我担心在Web应用程序中没有可能的方法 . 如果您的用户在NAT或其他东西后面,您也无法获得IP .

    Update :虽然有些网站使用IP来限制用户(如rapidshare),但它们在NAT环境中无法正常工作 .

  • 7

    我想我应该与大家分享我的经验 . 好吧,我看到在某些情况下 REMOTE_ADDR 不会得到你想要的东西 . 例如,如果您在场景后面有一个负载均衡器,并且如果您尝试获取客户端的IP,那么您将遇到麻烦 . 我用我的IP掩蔽软件检查了它,我还检查了同事在不同的大陆 . 所以这是我的解决方案 .

    当我想知道客户端的IP时,我会尝试选择所有可能的证据,以便确定它们是否是唯一的:

    在这里,我发现了另一个sever-var,如果你想获得客户端的确切IP,它可以帮助你们 . 所以我正在使用: HTTP_X_CLUSTER_CLIENT_IP

    HTTP_X_CLUSTER_CLIENT_IP 总能获得客户端的确切IP . 在任何情况下,如果它没有给你 Value ,你应该寻找 HTTP_X_FORWARDED_FOR 因为它是第二个获得客户端IP的最佳候选者,然后是 REMOTE_ADDR var,它可能会或可能不会返回给你IP,但对我来说,拥有所有这些三是我发现监控它们的最佳方法 .

    我希望这可以帮助一些人 .

相关问题