Internet enabled IIS Site always returning Local IP 互联网启用的 IIS 网站始终返回本地 IP
问题:Internet enabled IIS Site always returning Local IP
原因:
- 当应用程序位于负载均衡器之后时,无法正确获取客户端的 IP 地址。
- 即使没有负载均衡器,也会在请求中设置 X-Forwarded-For 头部。
解决方法:
- 可以添加一些回退逻辑来处理负载均衡器的存在。
- 可以尝试使用 X-Forwarded-For 头部来获取客户端的 IP 地址。
- 如果 X-Forwarded-For 头部不存在或为空,则尝试使用 RemoteIpAddress 属性来获取客户端的 IP 地址。
- 如果 RemoteIpAddress 属性也为空,则尝试使用 REMOTE_ADDR 头部来获取客户端的 IP 地址。
- 如果以上方法都无法获取客户端的 IP 地址,则抛出异常。
代码示例:
public string GetRequestIP(bool tryUseXForwardHeader = true) { string ip = null; if (tryUseXForwardHeader) ip = GetHeaderValueAs("X-Forwarded-For").SplitCsv().FirstOrDefault(); if (ip.IsNullOrWhitespace() && _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress != null) ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString(); if (ip.IsNullOrWhitespace()) ip = GetHeaderValueAs ("REMOTE_ADDR"); if (ip.IsNullOrWhitespace()) throw new Exception("Unable to determine caller's IP."); return ip; } public T GetHeaderValueAs (string headerName) { StringValues values; if (_httpContextAccessor.HttpContext?.Request?.Headers?.TryGetValue(headerName, out values) ?? false) { string rawValues = values.ToString(); if (!rawValues.IsNullOrWhitespace()) return (T)Convert.ChangeType(values.ToString(), typeof(T)); } return default(T); } public static List SplitCsv(this string csvList, bool nullOrWhitespaceInputReturnsNull = false) { if (string.IsNullOrWhiteSpace(csvList)) return nullOrWhitespaceInputReturnsNull ? null : new List (); return csvList .TrimEnd(',') .Split(',') .AsEnumerable () .Select(s => s.Trim()) .ToList(); } public static bool IsNullOrWhitespace(this string s) { return String.IsNullOrWhiteSpace(s); }
注意事项:
- `_httpContextAccessor` 应通过 DI 进行注入。
- 使用这种解决方法时,应用程序部署在 Kestrel 和 Nginx 上时效果良好。
- 如果配置不正确,可能会导致 IP 地址被伪造,因此需要注意安全性。
- 如果使用静态类中的扩展方法 IsNullOrWhitespace 和 SplitCsv,则应将其放在静态类中,其他方法可以在控制器的上下文中使用。
建议:
- 最好使用内置的 `UseForwardedHeaders` 中间件来处理 IP 地址的获取,具体参考文档。