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

ead*_*dam 166 c# asp.net-core-mvc asp.net-core

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

Dav*_*den 226

API已更新.不确定它何时改变但是根据Damien Edwards在12月底的说法,你现在可以这样做:

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress;
Run Code Online (Sandbox Code Playgroud)

  • 这为我返回":: 1",这是IPv6格式.其他人如何看待127.0.0.1? (21认同)
  • 请注意,它返回“::1”,因为您在本地运行它,并且这就是本地运行时始终返回的内容。 (16认同)
  • 即使我远程连接,我总是得到127.0.0.1 (11认同)
  • 当我在IIS上发布他的网站并将其记录在一个文件上时,我对`RemoteIpAddress`总是`null`. (9认同)
  • 有没有其他人获得其IIS服务器的本地IP地址返回? (4认同)
  • context.HttpContext.Connection.RemoteIpAddress.MapToIPv4(); 这将返回 0.0.0.1 (4认同)
  • 看起来问题已在rc 2中修复 (3认同)
  • System.Net.IPAddress remoteIpAddress = this.Request.HttpContext.Connection.RemoteIpAddress; (3认同)
  • 这是正确的属性,但如果您有任何类型的反向代理、负载均衡器或涉及内容分发,您还需要根据 Johna 的回答配置 UseForwardedHeaders()。 (3认同)

cro*_*sek 63

可以添加一些回退逻辑来处理Load Balancer的存在.

此外,通过检查,X-Forwarded-For即使没有Load Balancer(可能是因为额外的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);
}
Run Code Online (Sandbox Code Playgroud)

假设_httpContextAccessor是通过DI提供的.

  • 如果配置不当,答案会很糟糕。如果有人找到真实服务器的 IP,则只需注入 X-Forwarded-For 标头即可伪造 IP。 (3认同)
  • 这是正确的答案。没有唯一的方法来获取IP地址,特别是当您的应用程序位于Nginx,负载均衡器或类似的设备之后时。谢谢! (2认同)

Joh*_*hna 57

在project.json中添加依赖项:

"Microsoft.AspNetCore.HttpOverrides": "1.0.0"
Run Code Online (Sandbox Code Playgroud)

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

  app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor |
            ForwardedHeaders.XForwardedProto
        });  
Run Code Online (Sandbox Code Playgroud)

而且当然:

using Microsoft.AspNetCore.HttpOverrides;
Run Code Online (Sandbox Code Playgroud)

然后,我可以使用以下方式获取IP:

Request.HttpContext.Connection.RemoteIpAddress
Run Code Online (Sandbox Code Playgroud)

在我的情况下,在VS中进行调试时我总是得到IpV6 localhost,但是当部署在IIS上时,我总是得到远程IP.

一些有用的链接: 如何在ASP.NET CORE中获取客户端IP地址?RemoteIpAddress始终为空

::1也许是因为:

IIS处的连接终止,然后转发到v.next Web服务器Kestrel,因此与Web服务器的连接确实来自localhost.(/sf/answers/2480968101/)

  • 需要指出需要在app.UseAuthentication()之前添加"app.UseForwardedHeaders ..."; 如果你使用indentity行 (6认同)
  • 这是正确的答案,也在关于反向代理的官方文档中有记录:https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?tabs=aspnetcore2x#为什么使用-A-反向代理服务器 (5认同)
  • 截至2020年12月最新版本为2.2.0 (3认同)
  • @HakanFıstık没有任何变化,`UseForwardedHeaders()`扩展方法和`ForwardedHeadersOptions`类始终在`Microsoft.AspNetCore.Builder`中,而`ForwardedHeaders`仍然在`Microsoft.AspNetCore.HttpOverrides`中 (3认同)
  • 这工作得很好,我已经在本地托管的 IIS 和 Azure 上进行了测试。两个地方都适用。 (2认同)
  • 在 .NET 5 中,命名空间是“Microsoft.AspNetCore.Builder” (2认同)

Kir*_*lla 16

您可以使用它IHttpConnectionFeature来获取此信息.

var remoteIpAddress = httpContext.GetFeature<IHttpConnectionFeature>()?.RemoteIpAddress;
Run Code Online (Sandbox Code Playgroud)

  • 它适用于 Kestrel 托管吗?在我的演示中,`httpContext.GetFeature&lt;IHttpConnectionFeature&gt;()` 始终为 `null`。 (2认同)
  • @JerryBian 根据此文档:https://github.com/aspnet/Docs/blob/master/aspnet/fundamentals/servers.rst#supported-features-by-server,Kestrel(尚)不支持 IHttpConnectionFeature。 (2认同)

hoj*_*.mi 14

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

services.AddHttpContextAccessor();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

然后做3步:

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

    private IHttpContextAccessor _accessor;
    
    Run Code Online (Sandbox Code Playgroud)
  2. DI 进入控制器的构造函数

    public SomeController(IHttpContextAccessor accessor)
    {
        _accessor = accessor;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 检索 IP 地址

    _accessor.HttpContext.Connection.RemoteIpAddress.ToString()
    
    Run Code Online (Sandbox Code Playgroud)

这是如何完成的。

  • 多么糟糕的答案 - IHttpContextAccessor 是为注入服务而设计的。HttpContext 可作为 Controller 上的属性使用,并且应该这样访问。 (4认同)
  • 这给了我::1。Asp.Net Core 2.2.,在本地主机上。 (2认同)
  • `::1` 是 IPv6 中的本地主机。IPv4 相当于“127.0.0.1” (2认同)
  • @slippyr4你没有实例化任何东西,你仍然在访问与控制器相同的东西。因此,除非有一些幕后魔法,否则我不知道你在这里咆哮是没有道理的。这个答案对于不使用 MVC 的人可能有用 (2认同)

fer*_*adz 12

var remoteIpAddress = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress;
Run Code Online (Sandbox Code Playgroud)

  • 过于复杂.MVC已经在内部调用它并将其放在`HttpContext.Connection.RemoteIpAddress`下. (5认同)

rad*_*vus 12

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

Request.HttpContext.Connection.RemoteIpAddress
Run Code Online (Sandbox Code Playgroud)

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

添加一点清晰度

我最初提到这可以在我的 HttpController 内的 MVC 项目中使用。

Request 对象可用,因为 myDataController派生自 ASP.NET MVCController类。

下面是 Microsoft 基类代码的片段,其中Request可以HttpRequest通过继承到派生自它的类来使用它。

#region Assembly Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.AspNetCore.Mvc.Core.dll
#endregion

#nullable enable

using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Mvc
{
    //
    // Summary:
    //     A base class for an MVC controller without view support.
    [Controller]
    public abstract class ControllerBase
    {
        protected ControllerBase();

        //
        // Summary:
        //     Gets the Microsoft.AspNetCore.Http.HttpResponse for the executing action.
        public HttpResponse Response { get; }
        //
        // Summary:
        //     Gets the Microsoft.AspNetCore.Http.HttpRequest for the executing action.
        public HttpRequest Request { get; }
Run Code Online (Sandbox Code Playgroud)


Sru*_*Suk 11

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

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

所以,我实现了@Johna(/sf/answers/2893499101/)和@David(/sf/answers/601814601/)的答案,谢谢他们!

在这里解决:

  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
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在您可以从remoteIpAddressresult获取 IPv4 地址

  • 为什么不使用`remoteIpAddress.MapToIPv4();`? (7认同)
  • 使用 `remoteIpAddress.MapToIPv4();`,我得到 *0.0.0.1* 值,而不是我的机器地址 (2认同)

MC9*_*000 8

这对我有用(DotNetCore 2.1)

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


Aag*_*age 7

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

手动读取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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:感谢@JawadAlShaikh@BozoJoe指出 IP 可以包含一个端口并且X-Forwarded-For可以包含多个 IP。

  • 我发现“IPAddress.Parse(header)”如果包含端口“ip:port”,则会抛出错误,因此应该进行检查,或者快速破解“IPAddress.Parse(header.Remove(header.IndexOf(': ')))` (3认同)

Nar*_*sht 6

注意:使用 localhost 时,IP 地址始终为“0.0.0.1”,但是当我使用 Nginx 在 AWS EC2 实例上托管应用程序时,我收到了正确的 Ip 地址。

将以下包添加到您的项目中:

"Microsoft.AspNetCore.HttpOverrides": "2.2.0"
Run Code Online (Sandbox Code Playgroud)

然后在Startup.cs的Configure()方法中添加以下内容(确保将其放在app.UseStaticFiles()和app.UseRouting()之前)

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
    
// app.UseStaticFiles();
// app.UseRouting();
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器类中,你可以使用以下代码获取IP地址:

IPAddress remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString();
Run Code Online (Sandbox Code Playgroud)


gor*_*ums 5

就我而言,我在 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) }
        });
Run Code Online (Sandbox Code Playgroud)

::ffff:172.17.0.1 是我在使用之前获得的 ip

Request.HttpContext.Connection.RemoteIpAddress.ToString();
Run Code Online (Sandbox Code Playgroud)


Say*_*ood 5

根据官方文档,如果您使用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();
    });
Run Code Online (Sandbox Code Playgroud)

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

app.UseForwardedHeaders();
Run Code Online (Sandbox Code Playgroud)

进一步假设在 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;
Run Code Online (Sandbox Code Playgroud)

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

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

请参阅Linux 和非 IIS 反向代理的转发方案配置 Nginx处理无效标头