ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

D
David Peden

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

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress;

当我在 IIS 上发布网站并将其记录在文件中时,RemoteIpAddress 对我来说始终是 null
即使我远程连接,我也总是得到 127.0.0.1
这将为我返回 IPv6 格式的“::1”。其他人如何看待 127.0.0.1?
是否有其他人返回他们的 IIS 服务器的本地 IP 地址?
只是提醒一下,它返回一个“::1”,因为你在本地运行它,这就是在本地运行时总是返回的。
J
Johna

在 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
G
Greg Gum

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

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

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 的实例中(或调整它)。第二个 2 字符串方法是从单独的静态扩展类中提取的。
这是一个很好的解决方案,尤其是当您的应用程序使用 Kestrel 并在 Linux 上使用 Nginx 托管时。
如果配置不当,答案很糟糕。如果有人找到真实服务器的 IP,则有人可以通过注入 X-Forwarded-For 标头来伪造 IP。
K
Kiran

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

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

它适用于 Kestrel 托管吗?在我的演示中,httpContext.GetFeature<IHttpConnectionFeature>() 始终为 null
@JerryBian 根据此文档:github.com/aspnet/Docs/blob/master/aspnet/fundamentals/…,Kestrel(尚)不支持 IHttpConnectionFeature。
@JerryBian 现在是
必须已弃用 - @feradz 版本在 RC-1 中适用于我
如何使用 request.HttpContext.Features
A
Aage

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

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

然后执行 3 步:

在你的 MVC 控制器中定义一个变量 private IHttpContextAccessor _accessor; DI 进入控制器的构造函数 public SomeController(IHttpContextAccessor accessor) { _accessor = accessor;检索 IP 地址 _accessor.HttpContext.Connection.RemoteIpAddress.ToString()

这就是它的完成方式。


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

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

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

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

并在这里解决:

在您的引用(依赖项/包)中添加 Microsoft.AspNetCore.HttpOverrides 包 在 Startup.cs 中添加此行 public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 您当前的代码 // 要添加的开始代码 // 以获取 IP 地址app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); // 添加结束代码 } 获取 IPAddress,在任何 Controller.cs IPAddress 中使用此代码 remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;字符串结果 = ""; if (remoteIpAddress != null) { // 如果我们获得了 IPV6 地址,那么我们需要向网络请求 IPV4 地址 // 这通常只发生在浏览器与服务器位于同一台机器上时。 if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { remoteIpAddress = System.Net.Dns.GetHostEntry(remoteIpAddress).AddressList .First(x => x.AddressFamily == System.Net.Sockets.AddressFamily .InterNetwork); } 结果 = remoteIpAddress.ToString(); }

现在您可以从 remoteIpAddress 或结果中获取 IPv4 地址


AddressFamily - 直到现在才听说过这个。
为什么不使用 remoteIpAddress.MapToIPv4();
使用 remoteIpAddress.MapToIPv4();,我得到 0.0.0.1 值,而不是我的机器地址
f
feradz
var remoteIpAddress = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress;

过于复杂。 MVC 已经在内部调用它并将其放在 HttpContext.Connection.RemoteIpAddress 下。
@Fred - 你的版本在 RC-1 中为我返回 null - IIS 和 Kestrel
我得到 ::1 值,而不是 IP 格式。
M
Manoj Choudhari

这对我有用(DotNetCore 2.1)

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

r
raddevus

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

Request.HttpContext.Connection.RemoteIpAddress

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


g
gorums

就我而言,我在 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();

C
CodingYourLife

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


A
Aage

在负载均衡器后面的 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 中的值可以包含 <ip>:port AND 字符串,其中包含多个值,例如 192.168.1.1, 192.168.100.100
当标头不包含“:”时,此代码会引发异常。 header.IndexOf(':') 返回 -1,这是 string.Remove() 不喜欢的。
G
Guy

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

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

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


L
Lion

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

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

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

networks:
  my-docker-network:
    ipv4_address: 192.168.3.2

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


S
Sayyed Dawood

根据官方文档,如果您使用 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


A
Ali Mumtaz

首先添加

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

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

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

希望这对你有用


l
lianggan13

尝试这个:

字符串 remoteHost = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";


正如目前所写的那样,您的答案尚不清楚。请edit添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以找到有关如何写出好答案的更多信息in the help center
G
Green

您还可以使用 api.db-ip.com 网络服务获取 IP 地址和位置。

该服务是免费的,但它有一个限制:每天 1,000 个请求。

public string GetRemoteIP()
{
    HttpClient client = new HttpClient();
    var result = client.GetStringAsync("https://api.db-ip.com/v2/free/self").Result;
    var ip = JsonSerializer.Deserialize<RemoteIPDto>(result.ToString()).IP;
    return ip;
}
public static string GetUserAddress()
{
      HttpClient client = new HttpClient();
      var result = client.GetStringAsync("https://api.db-ip.com/v2/free/self").Result;
      var location = result.ToString();
      return remoteAddress;
}

RemoteIPDto 类在哪里

public class RemoteIPDto
{
    [JsonPropertyName("ipAddress")]
    public string IP { get; set; }
    [JsonPropertyName("continentCode")]
    public string ContinentCode { get; set; }
    [JsonPropertyName("continentName")]
    public string ContinentName { get; set; }
    [JsonPropertyName("countryCode")]
    public string CountryCode { get; set; }
    [JsonPropertyName("countryName")]
    public string CountryName { get; set; }
    [JsonPropertyName("city")]
    public string City { get; set; }
}

A
Abrar Jahin

this link,有一个更好的解决方案。

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

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;

M
Mehdi Dehghani

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

S
Semih Can Bilgen
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);

M
Mustafa Bazghandi

您还可以从外部服务获取 IP。

public string GetIP()
{
    HttpClient client = new HttpClient();
    var result = client.GetStringAsync("https://jsonip.com/").Result;
    var ip = JsonSerializer.Deserialize<RemoteIPDto>(result.ToString()).IP;
    return ip;
}

RemoteIPDto 类在哪里

public class RemoteIPDto
{
    [JsonPropertyName("ip")]
    public string IP { get; set; }
    [JsonPropertyName("geo-ip")]
    public string GeoIp { get; set; }
    [JsonPropertyName("API Help")]
    public string ApiHelp { get; set; }
}

K
Kunal Burangi

尝试这个。

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

这只会让您获得 SERVER 主机名
P
Pang

要在 .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
这将获得服务器的主机名
同意其他人。这不会帮助开发人员获取客户端地址。