欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

基于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的问题详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。