2010-04-05 162 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; 
    } 
} 
相关问题