2010-04-05 204 views
260

我完全不熟悉ASP.NET MVC堆棧,我想知道簡單的Page對象和Request ServerVariables對象發生了什麼?如何在ASP.NET MVC中獲取客戶端的IP地址?

基本上,我想拉出客戶端PC的IP地址,但我不明白當前的MVC結構如何改變這一切。

據我所知,most of the variable objects has been replaced by the HttpRequest variants

有人關心分享一些資源? ASP.NET MVC世界中真的有很多東西需要學習。 :)

例如,我有這個當前函數的靜態類。如何使用ASP.NET MVC獲得相同的結果?

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

如何從控制器頁面調用此函數?

+0

https://www.nuget.org/packages/XFF – efaruk 2015-05-10 07:31:23

回答

360

簡單的答案是使用HttpRequest.UserHostAddress property。如果請求已經由一個傳遞

using System.Web; 

namespace Mvc.Helpers 
{ 
    public static class HelperClass 
    { 
     public static string GetIPHelper() 
     { 
      string ip = HttpContext.Current.Request.UserHostAddress; 
      .. 
     } 
    } 
} 

BUT,

示例:從控制器內:

using System; 
using System.Web.Mvc; 

namespace Mvc.Controllers 
{ 
    public class HomeController : ClientController 
    { 
     public ActionResult Index() 
     { 
      string ip = Request.UserHostAddress; 

      ... 
     } 
    } 
} 

示例:從輔助類內,或更多,proxy serversHttpRequest.UserHostAddress property返回的IP地址將是最後一個代理服務器的IP地址,提出了要求。

代理服務器可能使用事實上標準放置客戶端的IP地址在X-Forwarded-For HTTP頭。除了不保證請求具有X-Forwarded-For標頭,也不保證X-Forwarded-For不是SPOOFED


原來的答案

Request.UserHostAddress 

上面的代碼提供了客戶端的IP地址,而不訴諸尋找一個集合。請求屬性在控制器(或視圖)中可用。因此強似Page類到你的功能,你可以傳遞一個Request對象來獲得相同的結果:

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

這是一個很好的答案;我從來沒有見過X_Forwarded_For頭。我閱讀了關於它的維基頁面,但是真的會感興趣爲什麼它會是多值的,或者你看過的真實世界的地方。 – LamonteCristo 2011-11-07 14:44:08

+6

@ makerofthings7:可能有多個值,因爲多個代理服務器可能會沿着客戶端的HTTP請求轉發。如果代理服務器「表現良好」(而不是有意匿名代理或者只是編程不好的代理服務器),則每個代理服務器都會在XFF標頭中的前一個代理上添加IP。 – 2012-04-09 01:57:08

+9

isPrivateIP方法做什麼? – eddiegroves 2012-04-09 07:16:54

162

Request.ServerVariables["REMOTE_ADDR"]應直接在視圖中或控制器操作方法主體(請求是MVC中的Controller類的屬性,而不是頁面)。

它正在工作..但你必須在真正的IIS上發佈而不是虛擬的。

+0

我如何從控制器端調用它? – melaos 2010-04-05 08:49:50

+0

查看更新。只要寫Request.ServerVariables [「...」]等 – ovolko 2010-04-05 08:55:22

+0

大聲笑,嘿工作,如果我想把它放入類對象如上所示會發生什麼?我還需要頁面對象嗎? – melaos 2010-04-05 09:36:00

19

在一類,你可以這樣調用它:

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

我在用這個一款剃鬚刀應用,效果極佳。

20

我有麻煩使用上述,我需要從控制器的IP地址。我最後使用了以下內容:

System.Web.HttpContext.Current.Request.UserHostAddress 
+2

從控制器你所要做的只是'HttpContext.Request.UserHostAddress' – 2013-04-13 01:13:36

+0

謝謝。在輔助類中不需要控制器或視圖上下文中需要的東西。這是一個很好的普遍答案。 +1 – ppumkin 2013-06-12 15:48:12

+0

@ppumkin你應該看看「使用」語句... – ganders 2014-01-30 13:31:36

91

很多代碼在這裏是非常有幫助的,但我爲我的目的進行了清理並添加了一些測試。這是我結束了:

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的測試(我用犀牛嘲笑嘲笑HttpRequestBase,這是M <HttpRequestBase>調用下面):

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); 
    } 
} 
+2

這總是返回運行我的應用程序的服務器的IP地址。 – 2014-04-16 15:31:37

+0

是否應該不返回'publicForwardingIps.First()'? – andy250 2017-07-11 14:11:48

+0

@Noah我猜這對IPv6地址不起作用? – AidanO 2018-01-09 15:09:52

2

我如何解釋我的網站作爲一個​​彈性負載均衡(ELB)背後:

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; 
    } 
} 
相關問題