























用户 → 家庭/公司路由器 → 外网 →(CDN/负载均衡/代理等)→ IIS服务器
X-Forwarded-For)传给下游。没有代理/负载,直接外网访问你服务:
有代理/负载(如CDN/网关/反向代理/IIS ARR等):
X-Forwarded-For(链条中的每一跳加一个IP)。你的扩展方法最终拿到的是“HTTP链最前端设备的公网IP”——即NAT后的地址,无法拿到局域网真实IP。

你只能看到 123.45.67.89,而没有办法得知 192.168.1.20。
如你需要进一步区分用户(家庭内多台机器),可以考虑:
public class ClientIpResolverHelper { #region 内部私有方法 private static string NormalizeIp(string ip) { if (string.IsNullOrEmpty(ip)) return null; if (!IPAddress.TryParse(ip, out var address)) return ip; if (address.IsIPv4MappedToIPv6) return address.MapToIPv4().ToString(); return address.ToString(); } private static bool IsPrivateIp(string ip) { if (!IPAddress.TryParse(ip, out var address)) return false; return IsPrivateIp(address); } private static bool IsPrivateIp(IPAddress address) { if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { return address.IsIPv6LinkLocal || address.IsIPv6SiteLocal || address.ToString().StartsWith("fc") || // Unique local address.ToString().StartsWith("fd"); } var bytes = address.GetAddressBytes(); return (bytes[0] == 10) || // 10.0.0.0/8 (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) || // 172.16.0.0/12 (bytes[0] == 192 && bytes[1] == 168) || // 192.168.0.0/16 (bytes[0] == 127); // 127.0.0.0/8 } #endregion /// <summary> /// 获取客户端IP /// </summary> /// <param name="htc"></param> /// <returns></returns> public static string GetClientIp(HttpContext htc) { HttpContext hct = GDCHttpContext.Current; var remoteIp = hct.Connection.RemoteIpAddress?.ToString(); // 如果不是私有 IP,直接返回(直连客户端) if (!string.IsNullOrEmpty(remoteIp) && !IsPrivateIp(remoteIp)) { return NormalizeIp(remoteIp); } // 尝试从转发头获取 var forwarded = hct.Request.Headers["X-Forwarded-For"].FirstOrDefault() ?? hct.Request.Headers["X-Real-IP"].FirstOrDefault(); if (string.IsNullOrEmpty(forwarded)) { return NormalizeIp(remoteIp) ?? "unknown"; } // 安全处理:从右向左遍历,找到最后一个可信的公网 IP var ips = forwarded.Split(',') .Select(s => s.Trim()) .Where(s => !string.IsNullOrEmpty(s)) .ToList(); // 遍历顺序:从离服务器最近的代理向客户端方向检查 for (int i = ips.Count - 1; i >= 0; i--) { var ip = ips[i]; if (IPAddress.TryParse(ip, out var address)) { // 如果是公网 IP,返回它 if (!IsPrivateIp(address)) { return NormalizeIp(address.ToString()); } } } // 如果全是内网 IP,返回第一个(最原始的) return NormalizeIp(ips.FirstOrDefault()) ?? "unknown"; } }
还有一步很重要:
//HttpContext.Connection.RemoteIpAddress 会自动变为X-Forwarded-For的第一个IP。 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。