You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Blazor 9部署在Azure中如何捕获客户端IP地址?

解决方案:Azure托管.NET 9 Blazor InteractiveServer获取客户端IP

针对你遇到的Azure部署后HttpContext丢失、作用域服务异常初始化的问题,以下是两个可靠的实现方案:

方案1:通过SignalR连接上下文捕获IP

Blazor InteractiveServer基于SignalR通信,每个客户端连接对应独立的HubConnectionContext,可直接从中获取真实客户端IP,不受后续渲染周期影响。

  1. 创建IP存储的Scoped服务(InteractiveServer模式下Scoped绑定单个客户端连接):
public interface IClientIpStore
{
    string ClientIp { get; set; }
}

public class ClientIpStore : IClientIpStore
{
    public string ClientIp { get; set; } = string.Empty;
}
  1. 实现SignalR Hub过滤器,在连接建立时捕获IP:
public class ClientIpCaptureFilter : IHubFilter
{
    private readonly IClientIpStore _ipStore;

    public ClientIpCaptureFilter(IClientIpStore ipStore)
    {
        _ipStore = ipStore;
    }

    public async ValueTask<object?> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next)
    {
        // 仅首次连接时捕获IP
        if (string.IsNullOrEmpty(_ipStore.ClientIp))
        {
            var httpContext = invocationContext.Context.GetHttpContext();
            if (httpContext != null)
            {
                // 优先取Azure反向代理传递的真实客户端IP
                _ipStore.ClientIp = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault() 
                                   ?? httpContext.Connection.RemoteIpAddress?.ToString();
            }
        }
        return await next(invocationContext);
    }
}
  1. 在Program.cs注册服务和过滤器:
builder.Services.AddScoped<IClientIpStore, ClientIpStore>();
builder.Services.AddSignalR(options =>
{
    options.AddFilter<ClientIpCaptureFilter>();
});
  1. 组件中注入使用:
@inject IClientIpStore IpStore

<p>客户端IP:@IpStore.ClientIp</p>

方案2:初始请求时将IP存入Claims

利用首次HTTP请求的HttpContext将IP写入用户Claims,后续通过AuthenticationStateProvider读取,无需依赖HttpContext的持续存在。

  1. 自定义中间件处理初始请求:
public class ClientIpClaimsMiddleware
{
    private readonly RequestDelegate _next;

    public ClientIpClaimsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 为匿名用户添加临时IP Claim
        if (!context.User.Identity?.IsAuthenticated ?? true)
        {
            string clientIp = context.Request.Headers["X-Forwarded-For"].FirstOrDefault() 
                              ?? context.Connection.RemoteIpAddress?.ToString();
            if (!string.IsNullOrEmpty(clientIp))
            {
                var identity = new ClaimsIdentity(new[] { new Claim("ClientIp", clientIp) }, "temp");
                context.User = new ClaimsPrincipal(identity);
            }
        }
        await _next(context);
    }
}
  1. 在Program.cs注册中间件(放在Blazor Hub映射前):
app.UseMiddleware<ClientIpClaimsMiddleware>();
app.MapBlazorHub();
  1. 组件中读取Claims:
@inject AuthenticationStateProvider AuthStateProvider

<p>客户端IP:@ClientIp</p>

@code {
    private string ClientIp = "未知";

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        ClientIp = authState.User.FindFirst("ClientIp")?.Value ?? ClientIp;
    }
}

关键配置:处理Azure反向代理

Azure部署时必须配置转发头,否则获取到的是代理服务器IP而非真实客户端IP,在Program.cs添加:

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    // 允许Azure内部代理IP段
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.0/8"));
    options.KnownProxies.Add(IPAddress.Parse("100.64.0.0/10"));
});

// 放在UseAuthentication之前执行
app.UseForwardedHeaders();

内容的提问来源于stack exchange,提问作者paultechguy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:13:27