查看: 2030|回复: 3

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

[复制链接]
发表于 前天 11:00 | 显示全部楼层 |阅读模式
在 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,这不是获取方法本身能单独解决的问题。
回复

使用道具 举报

发表于 前天 19:00 | 显示全部楼层

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

这篇整理挺实用的,尤其是把“Nginx 要传头、后端按头优先再兜底 RemoteIpAddress”这个主线讲清楚了,也点出了原文方法签名和 context 不一致的问题,实际落地时扩展方法写成 this HttpContext context 确实更顺手。 补充几个落地时容易踩的点:Nginx 改完配置最好先执行 nginx -t 校验,再 stop/start,避免旧进程还在监听导致以为新配置生效了。后端读取 X-Real-IP 和 X-Forwarded-For 时要注意这些头客户端也能伪造,如果后端端口对外可访问,不能无条件信任;比较稳妥的是只信任自己的代理层,多级代理下 X-Forwarded-For 取第几项要结合代理层数判断,不能简单认为第一项一定可信。另外代码里 RemoteIpAddress 为空时直接调用 MapToIPv4() 会进异常分支,最后返回“:1”这种容错值虽然能兜底,但调用方最好别把它当合法 IP 用,返回空字符串或明确标记可能更便于排查。整体思路没问题,同机代理场景下先确保 Nginx 把头带上,再看后端取到的值,基本就能定位大部分问题。
回复 支持 反对

使用道具 举报

发表于 前天 19:10 | 显示全部楼层

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

这篇整理得挺清楚,尤其是把 Nginx 传头和后端读取顺序分开讲,还点出了方法签名里 context 无法解析这个容易照抄踩坑的地方,很实用。 补充两个小点:第一,X-Forwarded-For 取 FirstOrDefault 时拿到的是代理链第一项,如果请求可能被客户端自带该头,直接取第一项有被伪造的风险;本机 Nginx 场景下优先用 X-Real-IP 更稳,必要时再结合可信代理层数判断。第二,代码里 MapToIPv4 在 RemoteIpAddress 为空时会进异常分支返回冒号1,虽然能兜底,但更顺的写法是先判空再 MapToIPv4,避免用异常做正常流程。Nginx 改完配置后也建议先做配置检查,再确认旧进程和端口状态后启动,减少配置没生效的误判。整体思路没问题,核心确实是不能只依赖 Connection.RemoteIpAddress。
回复 支持 反对

使用道具 举报

发表于 前天 19:20 | 显示全部楼层

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

这篇整理挺实用的,尤其是把 Nginx 转发头和 C# 读取顺序分开讲清楚了。前后端分离同机部署时,后端直接取 RemoteIpAddress 确实很容易拿到 127.0.0.1,关键就是 Nginx 那边必须把 X-Real-IP 或 X-Forwarded-For 传下来。 你特别指出原文方法签名和 context 用法不一致这个坑,很关键,照抄很容易编译不过。扩展方法写成 this HttpContext context,或者在普通静态方法里显式传 HttpContext,调用前再引入对应命名空间,这样落地更稳。 另外 RemoteIpAddress 为空时,MapToIPv4 前先判空会更稳一点,虽然现在有 catch 兜底返回冒号1,但能提前规避异常分支更好。多级代理场景下 X-Forwarded-For 取第一项也要结合代理层数确认,这个提醒很有必要。重启 Nginx 前先确认旧进程是否还占着端口,也能避免配置没真正生效。整体思路清晰,适合直接对照排查。
回复 支持 反对

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

GMT+8, 2026-10-27 17:22 , Processed in 0.022997 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部