如何在 ASP.NET Core 中获取客户端 IP 地址?

How do I get client IP address in ASP.NET Core?

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

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

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

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

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress;

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

此外,通过检查,X-Forwarded-For header 即使没有负载平衡器(可能是因为额外的 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://whosebug.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 提供的。

在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 本地主机,但是当部署在 IIS 上时,我总是得到远程 IP。

一些有用的链接: and RemoteIpAddress is always null

::1 可能是因为:

Connections termination at IIS, which then forwards to Kestrel, the v.next web server, so connections to the web server are indeed from localhost. ()

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

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

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

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

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

在 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()
    

这是怎么做的。

这对我有用 (DotNetCore 2.1)

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

就我而言,我在 DigitalOcean 上有 DotNet Core 2.2 Web App 运行,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();

要在 .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();

试试这个。

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

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

这个问题是因为你试图从你自己的机器上获取 IP,而 C# 试图 return IPv6 的混乱。

所以,我实现了@Johna () and @David () 的答案,感谢他们!

这里是解决方案:

  1. 在您的参考文献中添加 Microsoft.AspNetCore.HttpOverrides 包 (Dependencies/Packages)

  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. 要获取 IP 地址,请在您的任何 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 地址

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

手动阅读 X-Forwarded-For header 可以。 此代码假定此 header 包含一个 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。

运行 ASP.NET Core 2.1 behind a Traefik reverse Proxy on Ubuntu, 安装官方[=13=后我需要在KnownProxies设置它的网关IP ] 包裹

        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 中指定其网关就足够了。

在 .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

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;

@crokusek

的简短版本
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;
}

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

Request.HttpContext.Connection.RemoteIpAddress

现在看起来比过去简单多了。

根据官方文档,如果您正在使用 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 proxies, Configure Nginx and Dealing with invalid headers

首先添加

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

希望这对你有用

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

试试这个:

string remoteHost = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";