查看: 266|回复: 0

NetCore前后端分离Nginx代理获取真实客户端IP

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在 NetCore + Vue 前后端分离部署中,前端常由 Nginx 托管,并在同一台服务器上把请求代理到 localhost:5000。若 Nginx 只做 proxy_pass 而没有把客户端地址传给后端,HttpContext.Connection.RemoteIpAddress 取到的往往是代理机地址;代理机和后端在同一台机器时,就会表现为 127.0.0.1 等本机 IP。解决思路分两步:Nginx 增加转发头,后端按头优先、连接地址兜底读取。

一、Nginx 传递真实客户端地址
在 location / 中增加 X-Real-IP 和 X-Forwarded-For:
  1. location / {
  2.     proxy_pass http://localhost:5000;
  3.     proxy_set_header X-Real-IP $remote_addr;
  4.     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  5. }
复制代码
其中 X-Real-IP 保存 $remote_addr,X-Forwarded-For 用 $proxy_add_x_forwarded_for 追加代理链信息。后端应先读这两个请求头,再回退到 RemoteIpAddress。

二、重启 Nginx 与停止异常
以管理员身份进入 Nginx 目录后停止:
  1. D:\nginx-1.21.5>nginx -s stop
复制代码
启动:
  1. D:\nginx-1.21.5>start nginx
复制代码
原文提到有时 nginx -s stop 不能停止 Nginx,可用资源管理器结束进程。实际排查时先确认旧进程是否仍在监听端口,再启动新进程,避免配置没有真正生效。

三、C# 通用获取 IP 方法
原文给出的读取顺序是:X-Real-IP、X-Forwarded-For 的第一项、RemoteIpAddress.MapToIPv4()、RemoteIpAddress.ToString(),最后回退 127.0.0.1;发生异常时返回冒号1。封装为 HttpContext 扩展方法可这样写:
  1. using Microsoft.AspNetCore.Http;
  2. using System.Linq;
  3. public static class HttpContextIpExtensions
  4. {
  5.     /// <summary>
  6.     /// 获取客户Ip
  7.     /// </summary>
  8.     /// <param name="context"></param>
  9.     /// <returns></returns>
  10.     public static string fnGetClientUserIp(this HttpContext context)
  11.     {
  12.         try
  13.         {
  14.             var userHostAddress = context.Request.Headers["X-Real-IP"].ToString();
  15.             if (string.IsNullOrWhiteSpace(userHostAddress))
  16.             {
  17.                 userHostAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
  18.             }
  19.             if (string.IsNullOrWhiteSpace(userHostAddress))
  20.             {
  21.                 userHostAddress = context.Connection.RemoteIpAddress.MapToIPv4()?.ToString();
  22.             }
  23.             if (string.IsNullOrWhiteSpace(userHostAddress))
  24.             {
  25.                 userHostAddress = context.Connection.RemoteIpAddress.ToString();//这个是直接IP,如果经过反向代理IP会变成代理机的,如果代理机就是本机就会变成127.0.0.1
  26.             }
  27.             if (!string.IsNullOrWhiteSpace(userHostAddress))
  28.             {
  29.                 return userHostAddress;
  30.             }
  31.             return "127.0.0.1";
  32.         }
  33.         catch (Exception ex)
  34.         {
  35.             return ":1";
  36.         }
  37.     }
  38. }
复制代码
调用方式:
  1. string sIp = this.HttpContext.fnGetClientUserIp();
复制代码
如果把它定义成普通类内静态方法,则按原文方式调用:
  1. string sIp = 你的Class类名.fnGetClientUserIp();
复制代码
这里要注意:原文第一段方法签名写的是 fnGetClientUserIp(),方法体却直接使用了 context。单独照抄会出现 context 无法解析的问题。实际落地时,要么按上面的扩展方法签名写成 this HttpContext context,要么作为普通静态方法显式传入 HttpContext 参数;扩展方法还需要在调用处引入对应命名空间。

四、适用场景与注意点
这套写法适用于 NetCore 后端加 Vue 前端、由 Nginx 做本机反向代理的前后端分离项目。关键在于 Nginx 必须传 X-Real-IP 或 X-Forwarded-For,后端不能只依赖 Connection.RemoteIpAddress。多级代理时 X-Forwarded-For 可能包含多个地址,原文取 FirstOrDefault(),调用方应结合代理层数判断取哪一项;X-Real-IP 为空时要继续回退。MapToIPv4() 用于处理 IPv4 映射地址,RemoteIpAddress 为空时原写法可能进入异常分支,因此调用方要接受返回冒号1的容错结果。若只在同机代理且未传头,回退到的 RemoteIpAddress 仍可能是 127.0.0.1,这不是获取方法本身能单独解决的问题。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-25 13:32 , Processed in 0.024638 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部