ASP.NET Core 搭配 Nginx 的真实IP问题

原文:ASP.NET Core 搭配 Nginx 的真实IP问题

一.前言

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-IPX-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/lonelyxmas/p/10207299.html

时间: 2024-09-30 22:24:39

ASP.NET Core 搭配 Nginx 的真实IP问题的相关文章

ASP.NET获取用户端的真实IP

ASP.NET获取用户端的真实IP在各种场景都能用到,但是用户网端变幻莫测情况众多,获取真实IP还真是不容易啊.下面分享个比较好一点的方法: 获取IP初始版本 /// <summary> /// 获得当前页面客户端的IP /// Author:codeo.cn /// </summary> /// <returns>当前页面客户端的IP</returns> public static string GetIP() { string result = Stri

asp.net core 二 Nginx Supervisor 负载,监听

ASP.NET Core负载均衡集群搭建(CentOS7+Nginx+Supervisor+Kestrel) asp.net core在linux运行下,一但命令行退出,程序将停止,而且asp.net core的监听以及负载问题将在这里说明 参考连接:http://www.linuxidc.com/Linux/2016-11/136997.htm http://www.sohu.com/a/192683690_468635  https://www.cnblogs.com/ants/p/5732

首层nginx 传递 二级代理nginx 客户端真实IP的方法

首层nginx:先获取真实IP($remote_addr),再将真实IP传递给X-Forwarded-For    proxy_set_header X-Real-IP $remote_addr;    proxy_set_header X-Forwarded-For $remote_addr; 二级代理nginx:设置从上级nginx传递过来的X-Forwarded-For为真实IP,日志文件设置获取用户真实IP的变量设置为$remote_addr即可.    set_real_ip_from

关于nginx获取真实ip,proxy_set_head设置头部信息的理解

$proxy_add_x_forwarded_for $http_x_forwarded_for 这两个的变量的值的区别,就在于,proxy_add_x_forwarded_for 比http_x_forwarded_for 多了一个$remote_addr的值 但是$remote_addr 只能获取到与服务器本身直连的上层请求ip,所以设置$remote_addr一般都是设置第一个代理上面 但是问题是,有时候是通过cdn访问过来的,那么后面web服务器获取到的,永远都是cdn 的ip 而非真是

tomcat 获取真实ip地址

tomcat日志记录nginx的真实ip 1.在nginx.conf设置如下 http { set_real_ip_from 10.168.38.0/24;    #通过该指令指定信任的地址,将会被替代为精确的IP地址 real_ip_header X-Forwarded-For;      #这个指令用于设置使用哪个头来替换IP地址.如果使用了X-Forwarded-For,那么该模块将会使用X-Forwarded-For头中的最后一个IP地址来替换前端代理的IP地址. } location

了解ASP.NET Core框架的本质

ASP.NET Core自身的运行原理和设计思想创建了一个 “迷你版” 的ASP.NET Core框架,并且利用这个 “极简” 的模拟框架阐述了ASP.NET Core框架最核心.最本质的东西.整个框架涉及到的核心代码不会超过200行,涉及到7个核心的对象. PPT下载源代码下载 目录1. 从Hello World谈起2. ASP.NET Core Mini3. Hello World 24. 第一个对象:HttpContext5. 第二个对象:RequetDelegate6. 第三个对象:Mi

通过极简模拟框架让你了解ASP.NET Core MVC框架的设计与实现[上篇]

<200行代码,7个对象--让你了解ASP.NET Core框架的本质>让很多读者对ASP.NET Core管道有了真实的了解.在过去很长一段时间中,有很多人私信给我:能否按照相同的方式分析一下MVC框架的设计与实现原理,希望这篇文章能够满足你们的需求.在对本章内容展开介绍之前,顺便作一下广告:<ASP.NET Core 3框架揭秘>已经开始销售,现时5折优惠还有最后4天,有兴趣的从这里入群购买. 目录一.Action元数据的解析     ActionDescriptor    

ASP.NET Core 2.1发布/部署到Ubuntu并配置Nginx反向代理实现ip访问

一.准备 我用的是Ubuntu服务器器 [Ubuntu 18.04 x64] 和终端管理工具[Xshell] 二.安装 在服务器上安装.NET Core 三.部署程序 1.创建实例程序 可以直接使用.NET Core 的命令创建一个ASP.NET Core 示例网站应用程序,创建目录 /home/myuser/firstapp,执行命令: dotnet new mvc 接着,发布刚才创建的ASP.NET Core 网站发网站目录,所以,我们先创建一个网站发布目录:/var/www/firstap

一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx、supervisor、mysql环境搭建

作为.neter,看到.net core 2.0的正式发布,心里是有点小激动的,迫不及待的体验了一把,发现速度确实是快了很多,其中也遇到一些小问题,所以整理了一些学习笔记: 阅读目录 环境说明 安装CentOS7 安装.NET Core SDK for CentOS7 搭建ftp服务器 安装mysql 部署ASP.NET Core应用程序 配置Nginx 配置守护服务(Supervisor) 环境说明 服务器系统:CentOS 7.3 64位 相关工具:putty.Xftp 服务器软件软件:.n