409

我们必须Request.UserHostAddress在 ASP.NET 中获取 IP 地址,但这通常是用户的 ISP 的 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。

我理解的好吗?

4

21 回答 21

478

通常,您会想知道访问您网站的人的 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 的博客文章“问题:HTTP_X_FORWARDED_FOR 返回多个 IP 地址”

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
于 2009-04-11T17:03:57.243 回答
147

正如其他人所说,你不能做你所要求的。如果您描述了您要解决的问题,也许有人可以提供帮助?

例如

  • 您是否正在尝试唯一标识您的用户?
  • 您可以使用 cookie 或会话 ID 代替 IP 地址吗?

编辑您在服务器上看到的地址不应该是 ISP 的地址,正如您所说的那样,范围很大。宽带上家庭用户的地址将是他们路由器的地址,因此屋内的每台设备在外面看起来都是相同的,但路由器使用 NAT 来确保流量正确路由到每台设备。对于从办公环境访问的用户,地址可能对所有用户都是相同的。使用 IP 地址作为 ID 的站点冒着出错的风险 - 您提供的示例很好,但它们经常失败。例如,我的办公室在英国,突破点(我“出现”在互联网上的地方)在我们主要 IT 设施所在的另一个国家,所以从我的办公室来看,我的 IP 地址似乎不在英国。因此,我无法访问仅限英国的网页内容,例如 BBC iPlayer)。在任何给定时间,我的公司都会有数百甚至数千人似乎从同一个 IP 地址访问网络。

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

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

这个关于 NAT 的维基百科链接将为您提供一些背景知识。

于 2009-04-09T18:37:14.883 回答
88

更新: 感谢布鲁诺洛佩斯。如果可能有多个 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"];
    }
于 2012-03-05T13:27:49.943 回答
26

如果是c#这么看的话,很简单

string clientIp = (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? 
                   Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim();
于 2013-01-30T14:41:08.617 回答
25

您还认为用户 IP 地址是什么?如果您想要网络适配器的 IP 地址,恐怕在 Web 应用程序中无法做到。如果您的用户在 NAT 或其他东西之后,您也无法获得 IP。

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

于 2009-04-09T18:21:15.330 回答
23

我想我应该和大家分享我的经验。好吧,我看到在某些情况下REMOTE_ADDR不会为您提供所需的内容。例如,如果您在后台有一个负载均衡器,并且您正在尝试获取客户端的 IP,那么您将遇到麻烦。我用我的 IP 屏蔽软件检查了它,还检查了我在不同大陆的同事。所以这是我的解决方案。

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

在这里,我找到了另一个 sever-var,如果您想获得客户端的确切 IP,它可以为您提供帮助。所以我正在使用:HTTP_X_CLUSTER_CLIENT_IP

HTTP_X_CLUSTER_CLIENT_IP始终为您提供客户端的确切 IP。在任何情况下,如果它没有为您提供价值,那么您应该寻找HTTP_X_FORWARDED_FOR因为它是获得客户端 IP 的第二个最佳候选者,然后是REMOTE_ADDR var,它可能会或可能不会返回您的 IP,但对我来说拥有所有这些三是我发现最好的东西来监控它们。

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

于 2012-11-15T16:27:24.317 回答
16

您可以使用:

System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.GetValue(0).ToString();
于 2011-09-27T00:20:23.867 回答
14

IP 地址是“七层堆栈”中网络层的一部分。网络层可以对 IP 地址做任何想做的事情。这就是代理服务器、NAT、中继或其他任何东西所发生的情况。

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

于 2009-04-09T18:32:25.193 回答
13

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

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; }
        }
    }
}
于 2017-07-12T00:11:36.397 回答
11

如果你使用 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();
于 2016-07-23T22:03:38.267 回答
9
string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;
于 2014-07-15T07:38:15.493 回答
7

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

于 2011-08-04T15:22:47.123 回答
6

结合@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;
    }
}
于 2018-01-02T08:22:34.320 回答
4
public static class Utility
{
    public static string GetClientIP(this System.Web.UI.Page page)
    {
        string _ipList = page.Request.Headers["CF-CONNECTING-IP"].ToString();
        if (!string.IsNullOrWhiteSpace(_ipList))
        {
            return _ipList.Split(',')[0].Trim();
        }
        else
        {
            _ipList = page.Request.ServerVariables["HTTP_X_CLUSTER_CLIENT_IP"];
            if (!string.IsNullOrWhiteSpace(_ipList))
            {
                return _ipList.Split(',')[0].Trim();
            }
            else
            {
                _ipList = page.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (!string.IsNullOrWhiteSpace(_ipList))
                {
                    return _ipList.Split(',')[0].Trim();
                }
                else
                {
                    return page.Request.ServerVariables["REMOTE_ADDR"].ToString().Trim();
                }
            }
        }
    }
}

采用;

string _ip = this.GetClientIP();
于 2020-01-22T16:42:03.343 回答
3

在 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"];
}
于 2014-03-09T07:49:39.190 回答
1

在 NuGet 包安装Microsoft.AspNetCore.HttpOverrides 然后尝试:

public class ClientDeviceInfo
    {
        private readonly IHttpContextAccessor httpAccessor;

        public ClientDeviceInfo(IHttpContextAccessor httpAccessor)
        {
            this.httpAccessor = httpAccessor;
        }

        public string GetClientLocalIpAddress()
        {
            return httpAccessor.HttpContext.Connection.LocalIpAddress.ToString();
        }

        public string GetClientRemoteIpAddress()
        {
            return httpAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
        }

        public string GetClientLocalPort()
        {
            return httpAccessor.HttpContext.Connection.LocalPort.ToString();
        }

        public string GetClientRemotePort()
        {
            return httpAccessor.HttpContext.Connection.RemotePort.ToString();
        }
     }
于 2020-11-25T21:09:09.460 回答
0

很简单。试试吧:

var remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;

只是它 :))

于 2020-01-29T14:39:16.817 回答
-1

简单地

var ip =  Request.UserHostAddress;

就这样...

在此处输入图像描述

于 2021-08-31T05:14:45.290 回答
-2

大家好,您将找到的大多数代码将返回您的服务器 IP 地址而不是客户端 IP 地址。但是此代码返回正确的客户端 IP 地址。试一试。有关更多信息,请查看此

https://www.youtube.com/watch?v=Nkf37DsxYjI

要使用 javascript 获取本地 IP 地址,您可以使用将此代码放在脚本标记中

<script>
    var RTCPeerConnection = /*window.RTCPeerConnection ||*/
     window.webkitRTCPeerConnection || window.mozRTCPeerConnection;

         if (RTCPeerConnection) (function () {
             var rtc = new RTCPeerConnection({ iceServers: [] });
             if (1 || window.mozRTCPeerConnection) {      
                 rtc.createDataChannel('', { reliable: false });
             };

             rtc.onicecandidate = function (evt) {

                 if (evt.candidate)
                     grepSDP("a=" + evt.candidate.candidate);
             };
             rtc.createOffer(function (offerDesc) {
                 grepSDP(offerDesc.sdp);
                 rtc.setLocalDescription(offerDesc);
             }, function (e) { console.warn("offer failed", e); });


             var addrs = Object.create(null);
             addrs["0.0.0.0"] = false;
             function updateDisplay(newAddr) {
                 if (newAddr in addrs) return;
                 else addrs[newAddr] = true;
                 var displayAddrs = Object.keys(addrs).filter(function
(k) { return addrs[k]; });
                 document.getElementById('list').textContent =
displayAddrs.join(" or perhaps ") || "n/a";
             }

             function grepSDP(sdp) {
                 var hosts = [];
                 sdp.split('\r\n').forEach(function (line) { 
                     if (~line.indexOf("a=candidate")) {   
                         var parts = line.split(' '),   
                             addr = parts[4],
                             type = parts[7];
                         if (type === 'host') updateDisplay(addr);
                     } else if (~line.indexOf("c=")) {      
                         var parts = line.split(' '),
                             addr = parts[2];
                         updateDisplay(addr);
                     }
                 });
             }
         })(); else
         {
             document.getElementById('list').innerHTML = "<code>ifconfig| grep inet | grep -v inet6 | cut -d\" \" -f2 | tail -n1</code>";
             document.getElementById('list').nextSibling.textContent = "In Chrome and Firefox your IP should display automatically, by the power of WebRTCskull.";

         }




</script>
<body>
<div id="list"></div>
</body>

并且为了获取您的公共 IP 地址,您可以使用将此代码放在您的脚本标签中

  function getIP(json) {
    document.write("My public IP address is: ", json.ip);
  }


<script type="application/javascript" src="https://api.ipify.org?format=jsonp&callback=getIP"></script>
于 2018-12-31T05:05:31.580 回答
-3

用这个

Dns.GetHostEntry(Dns.GetHostName())
于 2012-09-09T09:39:02.780 回答
-7

尝试:

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;
}
于 2013-07-30T14:56:35.417 回答