【问题标题】:How do I get client IP address in ASP.NET Core?如何在 ASP.NET CORE 中获取客户端 IP 地址?
【发布时间】:2015-04-24 05:45:06
【问题描述】:

您能否告诉我在使用 MVC 6 时如何在 ASP.NET 中获取客户端 IP 地址。Request.ServerVariables["REMOTE_ADDR"] 不起作用。

【问题讨论】:

  • 示例:httpContext.GetFeature<IHttpConnectionFeature>().RemoteIpAddress

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

API 已更新。不确定何时更改,但在 12 月下旬 according to Damien Edwards,您现在可以这样做:

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress;

【讨论】:

  • RemoteIpAddress 对我来说始终是 null,当我在 IIS 上发布他的网站并将其记录在文件中时。
  • 即使远程连接,我总是得到 127.0.0.1
  • 这将为我返回 IPv6 格式的 "::1"。其他人如何看待 127.0.0.1?
  • 是否有其他人获得返回的 IIS 服务器的本地 IP 地址?
  • 请注意,它返回一个“::1”,因为您在本地运行它,这就是在本地运行时总是返回的内容。
【解决方案2】:

在 project.json 中添加一个依赖:

"Microsoft.AspNetCore.HttpOverrides": "2.2.0"

Startup.cs 中,在Configure() 方法中添加:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor |
    ForwardedHeaders.XForwardedProto
});  

当然还有:

using Microsoft.AspNetCore.HttpOverrides;

然后,我可以通过以下方式获取 ip:

Request.HttpContext.Connection.RemoteIpAddress

在我的例子中,在 VS 中调试时,我总是得到 IpV6 localhost,但是当部署在 IIS 上时,我总是得到远程 IP。

一些有用的链接: How do I get client IP address in ASP.NET CORE?RemoteIpAddress is always null

::1 可能是因为:

在 IIS 上的连接终止,然后转发到 v.next Web 服务器 Kestrel,因此与 Web 服务器的连接确实来自 localhost。 (https://stackoverflow.com/a/35442401/5326387)

编辑 12/2020:感谢SolidSnake:截至 2020 年 12 月,最新版本为 2.2.0

编辑 06/2021:感谢 Hakan Fıstık:在 .NET 5 中,命名空间是 Microsoft.AspNetCore.Builder

【讨论】:

  • 这是正确的答案,也记录在有关反向代理的官方文档中:docs.microsoft.com/en-us/aspnet/core/host-and-deploy/…
  • 需要指出,“app.UseForwardedHeaders...”需要在app.UseAuthentication()之前添加;行,以防您使用缩进
  • 这非常有效,我已经在本地托管的 IIS 和 Azure 上进行了测试。两个地方都适用。
  • 截至 2020 年 12 月,最新版本为 2.2.0
  • 在 .NET 5 中,命名空间是 Microsoft.AspNetCore.Builder
【解决方案3】:

可以添加一些回退逻辑来处理负载均衡器的存在。

此外,通过检查,X-Forwarded-For 标头碰巧在没有负载均衡器的情况下被设置(可能是因为额外的 Kestrel 层?):

public string GetRequestIP(bool tryUseXForwardHeader = true)
{
    string ip = null;

    // todo support new "Forwarded" header (2014) https://en.wikipedia.org/wiki/X-Forwarded-For

    // X-Forwarded-For (csv list):  Using the First entry in the list seems to work
    // for 99% of cases however it has been suggested that a better (although tedious)
    // approach might be to read each IP from right to left and use the first public IP.
    // http://stackoverflow.com/a/43554000/538763
    //
    if (tryUseXForwardHeader)
        ip = GetHeaderValueAs<string>("X-Forwarded-For").SplitCsv().FirstOrDefault();

    // RemoteIpAddress is always null in DNX RC1 Update1 (bug).
    if (ip.IsNullOrWhitespace() && _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress != null)
        ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();

    if (ip.IsNullOrWhitespace())
        ip = GetHeaderValueAs<string>("REMOTE_ADDR");

    // _httpContextAccessor.HttpContext?.Request?.Host this is the local host.

    if (ip.IsNullOrWhitespace())
        throw new Exception("Unable to determine caller's IP.");

    return ip;
}

public T GetHeaderValueAs<T>(string headerName)
{
    StringValues values;

    if (_httpContextAccessor.HttpContext?.Request?.Headers?.TryGetValue(headerName, out values) ?? false)
    {
        string rawValues = values.ToString();   // writes out as Csv when there are multiple.

        if (!rawValues.IsNullOrWhitespace())
            return (T)Convert.ChangeType(values.ToString(), typeof(T));
    }
    return default(T);
}

public static List<string> SplitCsv(this string csvList, bool nullOrWhitespaceInputReturnsNull = false)
{
    if (string.IsNullOrWhiteSpace(csvList))
        return nullOrWhitespaceInputReturnsNull ? null : new List<string>();

    return csvList
        .TrimEnd(',')
        .Split(',')
        .AsEnumerable<string>()
        .Select(s => s.Trim())
        .ToList();
}

public static bool IsNullOrWhitespace(this string s)
{
    return String.IsNullOrWhiteSpace(s);
}

假设 _httpContextAccessor 是通过 DI 提供的。

【讨论】:

  • 这是正确的答案。没有一种方法可以检索 IP 地址,特别是当您的应用程序位于 Nginx、负载均衡器或类似设备之后时。谢谢!
  • @crokusek...试图调整您的解决方案,但 VS 强迫我使用静态封装此代码的类。您的 Web 应用项目或解决方案的类库中是否有此代码?
  • 前 2 个方法应该在提供 __httpContextAccessor (或改编它)的实例中。后两个字符串方法是从单独的静态扩展类中提取的。
  • 这是一个很好的解决方案,尤其是当您的应用使用 Kestrel 并在 Linux 上使用 Nginx 托管时。
  • 如果配置不当,答案会很糟糕。如果有人找到了真实服务器的 IP,那么有人可以通过注入 X-Forwarded-For 标头来伪造 IP。
【解决方案4】:

您可以使用IHttpConnectionFeature 获取此信息。

var remoteIpAddress = httpContext.GetFeature<IHttpConnectionFeature>()?.RemoteIpAddress;

【讨论】:

  • 它是否适用于 Kestrel 托管?在我的演示中,httpContext.GetFeature&lt;IHttpConnectionFeature&gt;() 始终是 null
  • @JerryBian 根据此文档:github.com/aspnet/Docs/blob/master/aspnet/fundamentals/…,Kestrel(尚)不支持 IHttpConnectionFeature。
  • @JerryBian 现在是
  • 必须被弃用 - @feradz 版本在 RC-1 中适用于我
【解决方案5】:
var remoteIpAddress = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress;

【讨论】:

  • 过于复杂。 MVC 已经在内部调用它并将其放在HttpContext.Connection.RemoteIpAddress 下。
  • @Fred - 你的版本在 RC-1 中为我返回 null - IIS 和 Kestrel
【解决方案6】:

在 ASP.NET 2.1 中,在 StartUp.cs 添加此服务:

services.AddHttpContextAccessor();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();

然后执行 3 步:

  1. 在你的 MVC 控制器中定义一个变量

    private IHttpContextAccessor _accessor;
    
  2. DI 进入控制器的构造函数

    public SomeController(IHttpContextAccessor accessor)
    {
        _accessor = accessor;
    }
    
  3. 检索 IP 地址

    _accessor.HttpContext.Connection.RemoteIpAddress.ToString()
    

这就是它的完成方式。

【讨论】:

  • 这给了我 ::1。 Asp.Net Core 2.2.,在本地主机上。
  • ::1 是 IPv6 中的本地主机。 IPv4 等效于127.0.0.1
  • 多么糟糕的答案 - IHttpContextAccessor 是为注入服务而设计的。 HttpContext 可作为 Controller 上的属性使用,并且应该这样访问。
【解决方案7】:

我发现,有些人发现你得到的IP地址是:::1或0.0.0.1

这是因为您尝试从自己的机器上获取 IP,以及尝试返回 IPv6 的 C# 的混淆。

所以,我实现了@Johna (https://stackoverflow.com/a/41335701/812720) 和@David (https://stackoverflow.com/a/8597351/812720) 的答案,感谢他们!

在这里解决:

  1. 在您的引用(依赖项/包)中添加 Microsoft.AspNetCore.HttpOverrides 包

  2. 在 Startup.cs 中添加这一行

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // your current code
    
        // start code to add
        // to get ip address
        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });
        // end code to add
    
    }
    
  3. 要获取 IPAddress,请在任何 Controller.cs 中使用此代码

    IPAddress remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;
    string result = "";
    if (remoteIpAddress != null)
    {
        // If we got an IPV6 address, then we need to ask the network for the IPV4 address 
        // This usually only happens when the browser is on the same machine as the server.
        if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
        {
            remoteIpAddress = System.Net.Dns.GetHostEntry(remoteIpAddress).AddressList
    .First(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
        }
        result = remoteIpAddress.ToString();
    }
    

现在您可以从 remoteIpAddressresult

获取 IPv4 地址

【讨论】:

  • AddressFamily - 直到现在才听说过。
  • 为什么不使用remoteIpAddress.MapToIPv4();
【解决方案8】:

这对我有用(DotNetCore 2.1)

[HttpGet]
public string Get() 
{
    var remoteIpAddress = HttpContext.Connection.RemoteIpAddress;
    return remoteIpAddress.ToString();
}

【讨论】:

    【解决方案9】:

    就我而言,我在 DigitalOcean 上运行 DotNet Core 2.2 Web 应用程序,使用 docker 和 nginx 作为反向代理。使用 Startup.cs 中的此代码,我可以获得客户端 IP

    app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.All,
                RequireHeaderSymmetry = false,
                ForwardLimit = null,
                KnownNetworks = { new IPNetwork(IPAddress.Parse("::ffff:172.17.0.1"), 104) }
            });
    

    ::ffff:172.17.0.1 是我使用前得到的ip

    Request.HttpContext.Connection.RemoteIpAddress.ToString();
    

    【讨论】:

      【解决方案10】:

      在 .NET 5 中,我使用它通过 AWS fargate 上的容器检索客户端 IP。

      public static class HttpContextExtensions
      {
          //https://gist.github.com/jjxtra/3b240b31a1ed3ad783a7dcdb6df12c36
      
          public static IPAddress GetRemoteIPAddress(this HttpContext context, bool allowForwarded = true)
          {
              if (allowForwarded)
              {
                  string header = (context.Request.Headers["CF-Connecting-IP"].FirstOrDefault() ?? context.Request.Headers["X-Forwarded-For"].FirstOrDefault());
                  if (IPAddress.TryParse(header, out IPAddress ip))
                  {
                      return ip;
                  }
              }
              return context.Connection.RemoteIpAddress;
          }
      }
      

      你这样称呼它:

      var ipFromExtensionMethod = HttpContext.GetRemoteIPAddress().ToString();
      

      Source

      【讨论】:

        【解决方案11】:

        截至 2021 年 9 月 - ASP.NET Core (5.x) MVC 项目允许我在控制器中以这种方式获取 IP 地址:

        Request.HttpContext.Connection.RemoteIpAddress
        

        现在似乎比过去简单多了。

        【讨论】:

          【解决方案12】:

          在负载均衡器后面的 IIS 上运行 .NET core (3.1.4) 不适用于其他建议的解决方案。

          手动读取X-Forwarded-For 标头即可。 此代码假定此标头包含一个 IP。

          IPAddress ip;
          var headers = Request.Headers.ToList();
          if (headers.Exists((kvp) => kvp.Key == "X-Forwarded-For"))
          {
              // when running behind a load balancer you can expect this header
              var header = headers.First((kvp) => kvp.Key == "X-Forwarded-For").Value.ToString();
              // in case the IP contains a port, remove ':' and everything after
              ip = IPAddress.Parse(header.Remove(header.IndexOf(':')));
          }
          else
          {
              // this will always have a value (running locally in development won't have the header)
              ip = Request.HttpContext.Connection.RemoteIpAddress;
          }
          

          感谢@JawadAlShaikh@BozoJoe 指出IP 可以包含一个端口,而X-Forwarded-For 可以包含多个IP。

          【讨论】:

          • 我发现IPAddress.Parse(header) 包含端口ip:port 时会抛出错误,因此应该进行检查,或者快速破解IPAddress.Parse(header.Remove(header.IndexOf(':')))
          • 作为参考,IPEndPoint.Parse 有效地解析了 IP 地址和端口
          • @JawadAlShaikh 是正确的。 X-Forwarded-For 中的值可以包含&lt;ip&gt;:port AND 字符串,其中包含多个值,例如192.168.1.1, 192.168.100.100
          • 当标头不包含 ':' 时,此代码会引发异常。 header.IndexOf(':') 返回 -1,这是 string.Remove() 不喜欢的。
          【解决方案13】:

          首先,在 .Net Core 1.0 中 在控制器中添加using Microsoft.AspNetCore.Http.Features; 然后里面的相关方法:

          var ip = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress?.ToString();
          

          我阅读了其他几个无法编译的答案,因为它使用的是小写的 httpContext,导致 VS 使用 Microsoft.AspNetCore.Http 添加,而不是适当的使用,或者使用 HttpContext(编译器也是误导)。

          【讨论】:

            【解决方案14】:

            在 Ubuntu 上的 Traefik 反向代理后面运行 ASP.NET Core 2.1,我需要在安装官方 Microsoft.AspNetCore.HttpOverrides 包后将其网关 IP 设置为 KnownProxies

                    var forwardedOptions = new ForwardedHeadersOptions {
                        ForwardedHeaders = ForwardedHeaders.XForwardedFor,
                    };
                    forwardedOptions.KnownProxies.Add(IPAddress.Parse("192.168.3.1"));
                    app.UseForwardedHeaders(forwardedOptions);
            

            根据the documentation,如果反向代理不在本地主机上运行,​​则需要这样做。 Traefik 的docker-compose.yml 分配了静态IP地址:

            networks:
              my-docker-network:
                ipv4_address: 192.168.3.2
            

            或者,确保在此处定义已知网络以在 .NET Core 中指定其网关就足够了。

            【讨论】:

              【解决方案15】:

              来自this link,有更好的解决方案。

              在Startup.cs中,我们需要添加服务-

              public void ConfigureServices(IServiceCollection services)
              {
                  ........
                  services.AddHttpContextAccessor();
                  ........
              }
              

              然后在任何控制器或任何地方,我们都需要像这样通过依赖注入来使用它-

              private IHttpContextAccessor HttpContextAccessor { get; }
              
              public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IWebHostEnvironment env, IHttpContextAccessor httpContextAccessor)
                      : base(options)
              {
                  Environment = env;
                  HttpContextAccessor = httpContextAccessor;
                  //this.Database.EnsureCreated();
              }
              

              然后像这样获取IP-

              IPAddress userIp = HttpContextAccessor.HttpContext.Connection.RemoteIpAddress;
              

              【讨论】:

                【解决方案16】:

                @crokusek 的 answer 的短版

                public string GetUserIP(HttpRequest req)
                {
                    var ip = req.Headers["X-Forwarded-For"].FirstOrDefault();
                
                    if (!string.IsNullOrWhiteSpace(ip)) ip = ip.Split(',')[0];
                
                    if (string.IsNullOrWhiteSpace(ip)) ip = Convert.ToString(req.HttpContext.Connection.RemoteIpAddress);
                
                    if (string.IsNullOrWhiteSpace(ip)) ip = req.Headers["REMOTE_ADDR"].FirstOrDefault();
                
                    return ip;
                }
                

                【讨论】:

                  【解决方案17】:

                  根据官方文档,如果您使用的是Apache或Nginx集成,应在Startup.ConfigureServices方法中添加以下代码。

                  // using Microsoft.AspNetCore.HttpOverrides;
                  
                      services.Configure<ForwardedHeadersOptions>(options =>
                      {
                          options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | 
                              ForwardedHeaders.XForwardedProto;
                          // Only loopback proxies are allowed by default.
                          // Clear that restriction because forwarders are enabled by explicit 
                          // configuration.
                          options.KnownNetworks.Clear();
                          options.KnownProxies.Clear();
                      });
                  

                  然后最重要的是,在Configure 方法中使用

                  app.UseForwardedHeaders();
                  

                  进一步假设在 nginx conf 文件中的某个位置,使用

                  proxy_set_header   Host $host;
                  proxy_set_header   X-Real-IP $remote_addr;
                  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header   X-Forwarded-Host $server_name;
                  

                  现在X-Forwarded-For 中的第一个条目将是真正的客户端 IP。

                  重要提示:如果您想保护应用程序并且不允许攻击者注入 X-Forwarded-For,请阅读此answer

                  请参阅Forward the scheme for Linux and non-IIS reverse proxiesConfigure NginxDealing with invalid headers

                  【讨论】:

                    【解决方案18】:

                    先添加

                    Microsoft.AspNetCore.Http
                    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                    

                    ConfigureServices 在 Startup.cs 然后在您的控制器中添加以下代码

                       private IHttpContextAccessor _accessor;
                        
                      public LoginController(IHttpContextAccessor accessor)
                                {
                                  _accessor = accessor;
                                }
                    
                      public IEnumerable<string> Get()
                            {
                             var ip = _accessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
                             return new string[] { ip, "value" };
                            }
                    

                    希望这对你有用

                    【讨论】:

                      【解决方案19】:
                      using Microsoft.AspNetCore.Http;
                      using Microsoft.AspNetCore.Http.Features;
                      
                      public string GetClientIPAddress(HttpContext context)
                          {
                              string ip = string.Empty;
                      if (!string.IsNullOrEmpty(context.Request.Headers["X-Forwarded-For"]))
                              {
                                  ip = context.Request.Headers["X-Forwarded-For"];
                              }
                              else
                              {
                                  ip = context.Request.HttpContext.Features.Get<IHttpConnectionFeature>().RemoteIpAddress.ToString();
                              }
                              return ip;
                          }
                      

                      你想从哪里得到IP地址;

                      GetClientIPAddress(HttpContext);
                      

                      【讨论】:

                        【解决方案20】:

                        试试这个。

                        var host = Dns.GetHostEntry(Dns.GetHostName());
                                foreach (var ip in host.AddressList)
                                {
                                    if (ip.AddressFamily == AddressFamily.InterNetwork)
                                    {
                                         ipAddress = ip.ToString();
                                    }
                                }
                        

                        【讨论】:

                        • 这只会给你SERVER主机名
                        【解决方案21】:

                        要在 .NET Core 中获取 IP 地址和主机名,请将以下代码放入控制器中:

                        var addlist = Dns.GetHostEntry(Dns.GetHostName());
                        string GetHostName = addlist.HostName.ToString();
                        string GetIPV6 = addlist.AddressList[0].ToString();
                        string GetIPV4 = addlist.AddressList[1].ToString();
                        

                        【讨论】:

                        • 这不是获取主机的IP吗?寻找客户端IP
                        • 获取服务器的主机名
                        • 同意其他人。这无助于开发者获取客户端地址。
                        猜你喜欢
                        • 1970-01-01
                        • 2020-04-29
                        • 2020-05-16
                        • 2019-12-07
                        • 2022-01-22
                        • 1970-01-01
                        • 2011-02-04
                        • 2012-03-14
                        相关资源
                        最近更新 更多