How to get a user's client IP address in ASP.NET?

前端 未结 19 2887
时光取名叫无心
时光取名叫无心 2020-11-22 00:26

We have Request.UserHostAddress to get the IP address in ASP.NET, but this is usually the user\'s ISP\'s IP address, not exactly the user\'s machine IP address

19条回答
  •  日久生厌
    2020-11-22 00:46

    All of the responses so far take into account the non-standardized, but very common, X-Forwarded-For header. There is a standardized Forwarded header which is a little more difficult to parse out. Some examples are as follows:

    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
    

    I have written a class that takes both of these headers into account when determining a client's IP address.

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

    Below are some unit tests that I used to validate my solution:

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

提交回复
热议问题