请问如何在ASP中获取客户端IP地址?NET时使用MVC 6。 请求。ServerVariables["REMOTE_ADDR"]无效。
当前回答
可以添加一些回退逻辑来处理负载均衡器的存在。
此外,通过检查,即使没有负载均衡器,X-Forwarded-For报头也会被设置(可能是因为额外的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);
}
假设_httpContextAccessor通过DI提供。
其他回答
可以添加一些回退逻辑来处理负载均衡器的存在。
此外,通过检查,即使没有负载均衡器,X-Forwarded-For报头也会被设置(可能是因为额外的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);
}
假设_httpContextAccessor通过DI提供。
您可以使用IHttpConnectionFeature来获取此信息。
var remoteIpAddress = httpContext.GetFeature<IHttpConnectionFeature>()?.RemoteIpAddress;
也可以从外部服务获取IP。
public string GetIP()
{
HttpClient client = new HttpClient();
var result = client.GetStringAsync("https://jsonip.com/").Result;
var ip = JsonSerializer.Deserialize<RemoteIPDto>(result.ToString()).IP;
return ip;
}
RemoteIPDto类在哪里
public class RemoteIPDto
{
[JsonPropertyName("ip")]
public string IP { get; set; }
[JsonPropertyName("geo-ip")]
public string GeoIp { get; set; }
[JsonPropertyName("API Help")]
public string ApiHelp { get; set; }
}
在我的情况下,我用docker和nginx作为反向代理在DigitalOcean上运行DotNet Core 2.2 Web应用程序。使用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) }
});
::ffff:172.17.0.1是我在使用之前获得的ip
Request.HttpContext.Connection.RemoteIpAddress.ToString();
根据官方文档,如果你使用Apache或Nginx集成,以下代码应该添加到启动。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();
});
最重要的是,在配置方法中使用
app.UseForwardedHeaders();
进一步假设在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;
现在X-Forwarded-For中的第一个条目将是真正的客户端IP。
重要:如果你想保护应用程序,不允许攻击者注入x - forward - for,请阅读这个答案。
请参见转发Linux和非iis反向代理方案、配置Nginx和处理无效报头
推荐文章
- 函数应该返回空对象还是空对象?
- 如何转换日期时间?将日期时间
- 如何在c#中连接列表?
- 在c#中引用类型变量的“ref”的用途是什么?
- 防止在ASP中缓存。NET MVC中使用属性的特定操作
- 转换为值类型'Int32'失败,因为物化值为空
- c#中有任何连接字符串解析器吗?
- 在Linq中转换int到字符串到实体的问题
- 是否可以动态编译和执行c#代码片段?
- 创建自定义MSBuild任务时,如何从c#代码获取当前项目目录?
- c#和Java的主要区别是什么?
- 在c#中创建一个特定时区的DateTime
- .NET中的属性是什么?
- csproj文件中的“Service Include”是干什么用的?
- 如何使用try catch进行异常处理是最佳实践