如何在 Azure Functions C# 中获取客户端 IP 地址?

How to get client IP address in Azure Functions C#?

我正在使用 Azure Functions 在 C# 中编写一个函数,需要获取调用该函数的客户端的 IP 地址,这可能吗?

这是一个基于 here.

的答案
#r "System.Web"

using System.Net;
using System.Web;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    string clientIP = ((HttpContextWrapper)req.Properties["MS_HttpContext"]).Request.UserHostAddress;
    return req.CreateResponse(HttpStatusCode.OK, $"The client IP is {clientIP}");
}

你应该使用这些功能Get the IP address of the remote host

如果在本地调试预编译函数,

request.Properties["MS_HttpContext"] 不可用 request.Properties[RemoteEndpointMessageProperty.Name] 在 azure

上不可用
private string GetClientIp(HttpRequestMessage request)
{
    if (request.Properties.ContainsKey("MS_HttpContext"))
    {
        return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
    }

    if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
    {
        RemoteEndpointMessageProperty prop;
        prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
        return prop.Address;
    }

    return null;
}

2018 年 8 月 21 日更新: 现在 Azure Functions 在 LoadBalancer 后面 --> 我们必须检查 Request-Headers 以确定正确的客户端 IP

private static string GetIpFromRequestHeaders(HttpRequestMessage request)
    {
        IEnumerable<string> values;
        if (request.Headers.TryGetValues("X-Forwarded-For", out values))
        {
            return values.FirstOrDefault().Split(new char[] { ',' }).FirstOrDefault().Split(new char[] { ':' }).FirstOrDefault();
        }

        return "";
    }

现在 Azure 函数获得了一个 HttpRequest 参数,并且它们位于负载均衡器之后,此函数用于获取 IP 地址适合我:

private static string GetIpFromRequestHeaders(HttpRequest request)
{
      return (request.Headers["X-Forwarded-For"].FirstOrDefault() ?? "").Split(new char[] { ':' }).FirstOrDefault();
}

2019 年 10 月 18 日更新:

我试过的解决方案更简单快捷,在下面逐步提到。但是还有一些 lengthy/tricky 替代品可用 @ https://docs.microsoft.com/en-us/azure/azure-monitor/app/ip-collection:

  1. 登录到 Azure 门户。
  2. 登录后在同一浏览器中打开一个新标签页并拨打“http://Resources.Azure.Com
  3. 这是 Azure 后端服务门户,因此在进行更改时稍微小心一点会很好。
  4. 从左侧面板展开订阅部分,并展开应用洞察资源所在的 Azure 订阅。
  5. 展开资源组部分并展开应用洞察资源所在的资源组。
  6. 展开提供商部分并找到 Microsoft.Insights 提供商并将其展开。
  7. 展开“组件”部分并按名称找到并select您的 App Insight 实例。
  8. 在右上角将您的模式从只读更改为读写。
  9. 单击 Rest API 调用上的“编辑”按钮。
  10. 添加新的“"DisableIpMasking": true 属性 到属性部分。
  11. 按 PUT 按钮应用更改。
  12. 现在您的 App Insight 已启用,可以开始收集客户端 IP 地址。
  13. 对函数进行一些查询。
  14. 大约 5 到 10 分钟后刷新并测试 App Insights 数据。

这是一个基于我在 .Netcore 3.1 中看到的扩展方法。

public static IPAddress GetClientIpn(this HttpRequest request)
{
    IPAddress result = null;
    if (request.Headers.TryGetValue("X-Forwarded-For", out StringValues values))
    {
        var ipn = values.FirstOrDefault().Split(new char[] { ',' }).FirstOrDefault().Split(new char[] { ':' }).FirstOrDefault();
        IPAddress.TryParse(ipn, out result);
    }
    if (result == null)
    {
        result = request.HttpContext.Connection.RemoteIpAddress;
    }
    return result;
}

正如其他人已经提到的,查看 MS_HttpContext 的旧方法不再有效。此外,虽然查看 X-Forwarded-For 的 headers 的方法确实有效,但它仅在发布到 Azure 后才有效——当你 [=25] 时它不会 return 一个值=] 本地。如果您更喜欢在本地进行测试以最大程度地减少任何可能性,这可能很重要 cost-impact,但仍希望能够看到一切正常。

要在 运行 本地查看 IP 地址,请尝试以下操作:

using Microsoft.AspNetCore.Http;

然后:

String RemoteIP = ((DefaultHttpContext)req.Properties["HttpContext"])?.Connection?.RemoteIpAddress?.ToString();

这对我目前在 Azure Functions V3.0 中有效。

在 .NET 6.0 函数中,在操作的 Run() 函数中,可以访问 HttpRequest req 对象:

    public static class PingOperation
    {
        [FunctionName("ping")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

            log.LogInformation($"PingOperation requested from: {req.HttpContext.Connection.RemoteIpAddress}:{req.HttpContext.Connection.RemotePort}");

            string responseMessage = "This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }