一.前言

Nginx(Engine X)是一个高性能HTTP和反向代理服务,是由俄罗斯人伊戈尔·赛索耶夫为访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。 如果你是一名 ASP.NET Core 开发人员,并且你的 ASP.NET Core 应用部署在Linux上,相信你应该或多或少与 Nginx 有过接触,在我们将 ASP.NET Core 部署在 Linux 上时,它是被用做反向代理的最好选择之一。今天和大家聊一聊当我们使用了 Nginx 反向代理后,我们程序中获取真实IP(客户端真实ip,本文简称“真实IP”)的问题。

二.发现问题

1.安装 Nginx

这里我就选用我安装在 CentOS 7.2 上的 Nginx,在 CentOS 安装 Nginx 的同学可以参考我以前写的文章:CentOS 7 源码编译安装 Nginx

2.新建 ASP.NET Core 项目

第一步:

第二步:

3.编写代码

编辑 ValuesController

        private readonly HttpContext _context;        public ValuesController(IHttpContextAccessor accessor)        {_context = accessor.HttpContext;}        // GET api/values[HttpGet]        public ActionResult<IEnumerable<string>> Get(){            return Ok($"获取到的真实IP:{_context.Connection.RemoteIpAddress}");}

编辑 Startup

        public void ConfigureServices(IServiceCollection services)        {services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();}

4.测试

(1)将程序部署到服务器

本文略此步

(2)配置 Nginx 反向代理

新建配置文件 realiptest.conf

server {    listen 5002;    access_log  off;    location / {       proxy_pass http://localhost:5000; }
}

(3)测试访问

服务器地址:192.168.157.132

我本机地址:192.168.157.1

那么我本机通过访问 http://192.168.157.132:5002/api/values api获取到的ip地址应该是我本机的,即 192.168.157.1

通过浏览器访问验证:

可是却获取到了 127.0.0.1,这是因为 们的请求到了 Nginx,然后 Nginx 再将我们的请求转发到 ASP.NET Core 应用程序,实际上与 ASP.NET Core 应用程序 建立连接的是 Nginx ,所以获取到了服务器本地 IP (Nginx和程序部署在一台机子上)。请求流程如下图:

三.解决问题

修改程序代码以便显示更详细的信息:

ValuesController

        // GET api/values[HttpGet]               public ActionResult<IEnumerable<string>> Get(){StringBuilder sb=new StringBuilder();sb.AppendLine($"RemoteIpAddress:{_context.Connection.RemoteIpAddress}");                    if (Request.Headers.ContainsKey("X-Real-IP")){sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}");}                       if (Request.Headers.ContainsKey("X-Forwarded-For")){sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}");}                     return Ok(sb.ToString());}

修改反向代理配置:

server {    listen 5002;    access_log  off;    location / {       proxy_set_header   X-Real-IP        $remote_addr;       proxy_set_header   Host             $host;       proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;       proxy_pass                          http://localhost:5000;}
}

再次访问:

可以看到X-Real-IP 和 X-Forwarded-For请求头获取到了真实IP,我们通过修改 Nginx 配置,让程序接收到的请求信息携带真实IP。Nginx 通过在 X-Real-IP 、X-Forwarded-For 请求头设置了与它连接的远程ip

以上解决办法对于没有使用CDN是适用的。

四.使用CDN如何解决

我们的请求经过一个或者多个cdn结点以后,我们的程序如何获取真实IP呢,这就要看cdn服务商提供的解决办法了,一般有两种:

1.cdn服务商支持设置真实ip到某个指定的请求头,这样我们通过这个请求头就能获取了 。

2.一般经过cdn都会把真实ip经过的结点ip信息添加到头 X-Forwarded-For,我们取这个头里的第一个ip就是真实ip。

添加 nginx 配置,让他再次代理 5002 端口(前面添加的代理ASP.NET Core 程序),模拟cdn第二种方案:

server {    listen 5003;    access_log  off;    location / {       proxy_set_header   X-Real-IP        $remote_addr;       proxy_set_header   Host             $host;       proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;       proxy_pass                          http://192.168.157.132:5002;}
}

我们再次访问:

可以看到我们的真实ip被放到 X-Forwarded-For 请求头的第一个IP,X-Real-IP 获取到的是上一层代理的ip。

X-Forwarded-For 来自百度百科的解释:X-Forwarded-For 简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。标准格式如下:X-Forwarded-For: client1, proxy1, proxy2。请求流程如下图:

五.如何在代码里最小改动

经过上面的讲解,显而易见我们在代码里无法直接通过 RemoteIpAddress 获取真实ip,那么如果我们在编写代码时,很多地方直接采用 RemoteIpAddress获取真实ip怎么办,难道需要修改每一处吗,这里分享一个简单的解决办法,就是利用 ASP.NET Core 中间件给 RemoteIpAddress 重新赋值。

编写 RealIpMiddleware 中间件:

public class RealIpMiddleware{    private readonly RequestDelegate _next;    public RealIpMiddleware(RequestDelegate next)    {_next = next;}    public Task Invoke(HttpContext context)    {        var headers = context.Request.Headers;        if (headers.ContainsKey("X-Forwarded-For")){context.Connection.RemoteIpAddress=IPAddress.Parse(headers["X-Forwarded-For"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries)[0]);}        return _next(context);}
}

如果是前面提到的cdn的第一种情况,只需判断cdn服务商提供的特殊请求头就行了。

在Startup中配置

应放在最靠前的位置,以免有中间件获取到了未重置的IP地址。

保持前面的模拟cdn第二中情况架构,再次进行测试:

可以看到通过 RemoteIpAddress 获取到了真实ip。这种解决方案算是比较好的了。

这里提一下 Nginx RealIP Module 是 Nginx 获取真实ip的一个模块,有兴趣的同学可以自己去研究一下。

六.使用组件 Unicorn.AspNetCore

Unicorn.AspNetCore 里面我有封装处理ip的中间件。

通过nuget安装:

Install-Package Unicorn.AspNetCore

然后在 Program 中添加:

开源地址:https://github.com/UCPlan/Unicorn/tree/master/src/Infrastructure/Unicorn.AspNetCore/Middleware/RealIp

原文地址:https://www.cnblogs.com/stulzq/p/9946262.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

ASP.NET Core 搭配 Nginx 的真实IP问题相关推荐

  1. nodejs+nginx获取真实ip

    nodejs + nginx获取真实ip分为两部分: 第一.配置nginx: 第二.通过nodejs代码获取: 其他语言也是一样的,都是配置nginx之后,在http头里面获取"x-forw ...

  2. ASP.NET Core 实战:使用 Docker 容器化部署 ASP.NET Core + MySQL + Nginx

    一.前言 在之前的文章(ASP.NET Core 实战:Linux 小白的 .NET Core 部署之路)中,我介绍了如何在 Linux 环境中安装 .NET Core SDK / .NET Core ...

  3. nginx 获取真实ip

    问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我 ...

  4. 首层nginx 传递 二级代理,三级代理......多级代理nginx 客户端真实IP的方法

    首层nginx(172.25.10.1):先获取真实IP($remote_addr),再将真实IP传递给X-Forwarded-For     proxy_set_header X-Real-IP $ ...

  5. Nginx与真实IP

    配置了Nginx,Tomcat中的Web程序,获得的ip一直是"127.0.0.1",比较纳闷. 获得远程ip,已经判断了很多情况,为什么会这样呢? 正解  proxy_set_h ...

  6. ASP.NET Core Docker Nginx分权,多网站部署

    https://www.cnblogs.com/esofar/p/10694319.html 转载于:https://www.cnblogs.com/baiqian/p/10820476.html

  7. Asp.Net Core安全防护-客户端IP白名单限制

    前言 本篇展示了如何在ASP.NET Core应用程序中设置IP白名单验证的2种方式. 你可以使用以下2种方式: 用于检查每个请求的远程 IP 地址的中间件. MVC 操作筛选器,用于检查针对特定控制 ...

  8. 如何为ASP.NET Core设置客户端IP白名单验证

    本篇博文中展示了如何在ASP.NET Core应用程序中设置IP白名单验证的3种方式. 你可以使用一下3种方式: 使用中间件检查每个请求的远程IP地址 使用Action过滤器为指定的Controlle ...

  9. .NET Core+MySql+Nginx 容器化部署

    .NET Core容器化@Docker .NET Core容器化之多容器应用部署@Docker-Compose .NET Core+MySql+Nginx 容器化部署 GitHub-Demo:Dock ...

最新文章

  1. unigui中弹出对话框原窗体是没有了_最前线 | 微信对话框“搜一搜”功能上线,独辟蹊径的腾讯打着什么算盘?...
  2. Linux(ubuntu)下安装anaconda(64位)并配置jupyter notebook远程访问
  3. 这些建议需要竞赛组委会酌情考虑
  4. JVM -- 运行时栈帧结构简介
  5. 发表论文不用愁,十大技巧治秃头
  6. boost::fusion::unfused_typed用法的测试程序
  7. Flashback Data Archive(转)
  8. CRM Fiori my note应用的后台ABAP实现
  9. UIAlertController 类似相册拍照弹出框
  10. LeetCode-2: Add Two Numbers
  11. 会议 | 百度首席科学家吴华图灵大会演讲:NLP技术的演变与发展
  12. Word快速构建座位表
  13. RGBA(0,0,0,0)调色
  14. Linux的远程管理协议是什么,2-Linux权限与远程管理
  15. 动图文件太大怎么办?一招教你在线压缩GIF图片
  16. 17 年微软老兵,非典型跨领域 AI 科研之路
  17. 使用遇到的问题_使用网络线上教学系统遇到问题怎么办?
  18. 如何将本地项目上传至Gitee仓库(详细教程)
  19. 华擎计算机主板型号,华擎科技 新闻中心
  20. mysql语法错误:Every derived table must have its own alias

热门文章

  1. 《设计模式》3.结构型模式
  2. 【20181026T2】**图【最小瓶颈路+非旋Treap+启发式合并】
  3. Logstash 命令行参数
  4. 学习韩立刚老师IT运维课程,成为韩立刚老师正式学生,在全国范围为你就近推荐工作。...
  5. python 蓝牙模块pybluz安装
  6. [转]Multiple outputs from T4 made easy
  7. 百叶窗效果显示图片源码(c#)
  8. 2022版Win11重磅升级!
  9. 使用identity+jwt保护你的webapi(一)——identity基础配置
  10. Csv解析CsvFile