基于Nginx 反向代理获取真实IP的问题详解
程序员文章站
2022-04-26 14:38:05
一、前言
前文nginx 解决webapi跨域二次请求以及vue单页面问题 当中虽然解决了跨域问题带来的二次请求,但也产生了一个新的问题,就是如果需要获取用户ip的时候,...
一、前言
前文nginx 解决webapi跨域二次请求以及vue单页面问题 当中虽然解决了跨域问题带来的二次请求,但也产生了一个新的问题,就是如果需要获取用户ip的时候,获取的ip地址总是本机地址。
二、原因
由于nginx反向代理后,在应用中取得的ip都是反向代理服务器的ip,取得的域名也是反向代理配置的url的域名。
三、解决方案
解决该问题,需要在nginx反向代理配置中添加一些配置信息,目的将客户端的真实ip和域名传递到应用程序中。同时,也要修改获取ip地址的方法。
但是需要注意的是,通过nginx反向代理后,如果访问ip通过了几层代理,可能取得的ip地址是这种格式:clientip,proxy1,proxy2。
如果需要将ip地址插入到数据库的话,需要做防止注入。因此要对上述的ip地址的格式进行截取。
3.1 nginx 配置如下
server { listen 9461; # 监听端口号 server_name localhost 192.168.88.22; # 访问地址 location / { root 项目路径; # 例如:e:/publish/xxx/; index index.html; # 此处用于处理 vue、angular、react 使用h5 的 history时 重写的问题 if (!-e $request_filename) { rewrite ^(.*) /index.html last; break; } } # 代理服务端接口 location /api { proxy_pass http://localhost:9460/api;# 代理接口地址 # host配置以及域名传递 proxy_set_header host $host; proxy_set_header x-real-ip $remote_addr; proxy_set_header remote-host $remote_addr; proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for; } }
3.2 c#代码获取真实ip方法
#region ip(客户端ip地址) /// <summary> /// 客户端ip地址 /// </summary> public static string ip { get { var result = string.empty; if (httpcontext.current != null) { result = getwebclientip(); } if (string.isnullorwhitespace(result)) { result = getlanip(); } return result; } } /// <summary> /// 获取web客户端的ip /// </summary> /// <returns></returns> private static string getwebclientip() { var ip = getwebproxyrealip() ?? getwebremoteip(); foreach (var hostaddress in dns.gethostaddresses(ip)) { if (hostaddress.addressfamily == addressfamily.internetwork) { return hostaddress.tostring(); } } return string.empty; } /// <summary> /// 获取web远程ip /// </summary> /// <returns></returns> private static string getwebremoteip() { try { return httpcontext.current.request.servervariables["http_x_forwarded_for"] ?? httpcontext.current.request.servervariables["remote_addr"] ?? ""; } catch (exception e) { return string.empty; } } /// <summary> /// 获取web代理真实ip /// </summary> /// <returns></returns> private static string getwebproxyrealip() { var request = httpcontext.current.request; string ip = request.headers.get("x-forwarded-for"); if (string.isnullorempty(ip) || string.equals("unknown", ip, stringcomparison.ordinalignorecase)) { ip = request.headers.get("proxy-client-ip"); } if (string.isnullorempty(ip) || string.equals("unknown", ip, stringcomparison.ordinalignorecase)) { ip = request.headers.get("wl-proxy-client-ip"); } if (string.isnullorempty(ip) || string.equals("unknown", ip, stringcomparison.ordinalignorecase)) { ip = request.userhostaddress; } if (string.isnullorempty(ip)) { return string.empty; } // 可能存在如下格式:x-forwarded-for: client, proxy1, proxy2 if (ip.contains(", ")) { // 如果存在多个反向代理,获得的ip是一个用逗号分隔的ip集合,取第一个 // x-forwarded-for: client 第一个 string[] ips = ip.split(new string[1] {", "}, stringsplitoptions.removeemptyentries); var i = 0; for (i = 0; i < ips.length; i++) { if (ips[i] != "") { // 判断是否为内网ip if (false == isinnerip(ips[i])) { ipaddress realip; if (ipaddress.tryparse(ips[i], out realip) && ips[i].split('.').length == 4) { //合法ip return ips[i]; } return ""; } } } ip = ips[0];// 默认获取第一个ip地址 } return ip; } /// <summary> /// 判断ip地址是否为内网ip地址 /// </summary> /// <param name="ip">ip地址</param> /// <returns></returns> private static bool isinnerip(string ip) { bool isinnerip = false; ulong ipnum = ip2ulong(ip); /** * 私有ip * a类:10.0.0.0-10.255.255.255 * b类:172.16.0.0-172.31.255.255 * c类:192.168.0.0-192.168.255.255 * 当然,还有127这个网段是环回地址 */ ulong abegin = ip2ulong("10.0.0.0"); ulong aend = ip2ulong("10.255.255.255"); ulong bbegin = ip2ulong("172.16.0.0"); ulong bend = ip2ulong("10.31.255.255"); ulong cbegin = ip2ulong("192.168.0.0"); ulong cend = ip2ulong("192.168.255.255"); isinnerip = isinner(ipnum, abegin, aend) || isinner(ipnum, bbegin, bend) || isinner(ipnum, cbegin, cend) || ip.equals("127.0.0.1"); return isinnerip; } /// <summary> /// 将ip地址转换为long型数字 /// </summary> /// <param name="ip">ip地址</param> /// <returns></returns> private static ulong ip2ulong(string ip) { byte[] bytes = ipaddress.parse(ip).getaddressbytes(); ulong ret = 0; foreach (var b in bytes) { ret <<= 8; ret |= b; } return ret; } /// <summary> /// 判断用户ip地址转换为long型后是否在内网ip地址所在范围 /// </summary> /// <param name="userip">用户ip</param> /// <param name="begin">开始范围</param> /// <param name="end">结束范围</param> /// <returns></returns> private static bool isinner(ulong userip, ulong begin, ulong end) { return (userip >= begin) && (userip <= end); } /// <summary> /// 获取局域网ip /// </summary> /// <returns></returns> private static string getlanip() { foreach (var hostaddress in dns.gethostaddresses(dns.gethostname())) { if (hostaddress.addressfamily == addressfamily.internetwork) { return hostaddress.tostring(); } } return string.empty; } #endregion
以上这篇基于nginx 反向代理获取真实ip的问题详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
下一篇: 弘曕为什么会早逝?他做了什么激怒了乾隆?