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

一.前言

640?wx_fmt=jpeg

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 项目

第一步:

640?wx_fmt=png

第二步:

640?wx_fmt=png

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

通过浏览器访问验证:

640?wx_fmt=png

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

640?wx_fmt=png

三.解决问题

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

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;}
}

再次访问:

640?wx_fmt=png

可以看到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;}
}

我们再次访问:

640?wx_fmt=png

可以看到我们的真实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。请求流程如下图:

640?wx_fmt=png

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

经过上面的讲解,显而易见我们在代码里无法直接通过 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中配置

640?wx_fmt=png

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

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

640?wx_fmt=png

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

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

六.使用组件 Unicorn.AspNetCore

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

通过nuget安装:

Install-Package Unicorn.AspNetCore

然后在 Program 中添加:

640?wx_fmt=png

开源地址: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

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不止代码:保留道路(ybtoj 最小生成树)

文章目录题目描述解析代码thanks for reading!题目描述 解析 其实就是修建道路 我一开始只能想到枚举g去跑最小生成树 是m^2的算法&#xff08;50pts&#xff09; 但是其实每次加入的边只有一条 而且之前都不在最小生成树上的边以后也肯定不会在 所以可以建一个新的边的集合存…

P7515-[省选联考 2021A卷]矩阵游戏【差分约束】

正题 题目链接:https://www.luogu.com.cn/problem/P7515 题目大意 有一个n∗mn*mn∗m的矩形AAA&#xff0c;然后给出一个(n−1)∗(m−1)(n-1)*(m-1)(n−1)∗(m−1)的矩形BBB满足 Bi,jAi,jAi1,jAi,j1Ai1,j1B_{i,j}A_{i,j}A_{i1,j}A_{i,j1}A_{i1,j1}Bi,j​Ai,j​Ai1,j​Ai,j1​…

牛客题霸 [链表中环的入口节点] C++题解/答案

牛客题霸 [链表中环的入口节点] C题解/答案 题目描述 对于一个给定的链表&#xff0c;返回环的入口节点&#xff0c;如果没有环&#xff0c;返回null 拓展&#xff1a; 你能给出不利用额外空间的解法么&#xff1f; 题解&#xff1a; 判断环有个很巧妙的方法&#xff0c;之…

2021牛客暑期多校训练营8 F-Robots(bitset优化dp)

F-Robots 第一种第二种机器人直接O(n)O(n)O(n)判断即可。 第三种机器人暴力dp&#xff0c;用bitset优化。 bitset<250005> b[i][j] 表示从(i,j)(i,j)(i,j)能到达哪些点&#xff0c;第三种机器人向右向下转移即可。 状态压缩&#xff01; 时间复杂度O(qnn4w)O(qn\frac{…

不止代码:路径数量(ybtoj-最小生成树)

文章目录题目描述解析代码题目描述 解析 乍一看&#xff1a;是个水题啊&#xff01; 显然如果途径存在强连通的点&#xff0c;路径就会变为正无穷 所以缩点加拓扑dp以及一些特判应该就可以解决了&#xff01; 一交&#xff1a;40分。。。 然后就开始拆东墙补西墙的debug。。。…

重磅!!!微软发布.NET Core 2.2

我们很高兴地宣布发布.NET Core 2.2。它包括对运行时的诊断改进&#xff0c;对ARM32 for Windows和Azure Active Directory for SQL Client的支持。此版本中最大的改进是在ASP.NET Core中。ASP.NET Core 2.2和Entity Framework Core 2.2。您可以在Windows&#xff0c;macOS和Li…

Loj#2769-「ROI 2017 Day 1」前往大都会【最短路树,斜率优化】

正题 题目链接:https://loj.ac/p/2769 题目大意 给出nnn个点mmm条地铁线路&#xff0c;每条线路是一条路径。 求111到nnn的最短路且在最短路径的情况下相邻换乘点的距离平方和最大。 1≤n,m,∑si≤1061\leq n,m,\sum s_i\leq 10^61≤n,m,∑si​≤106 解题思路 首先肯定是在…

牛客题霸 [两个链表生成相加链表] C++题解/答案

牛客题霸 [两个链表生成相加链表] C题解/答案 题目描述 假设链表中每一个节点的值都在 0 - 9 之间&#xff0c;那么链表整体就可以代表一个整数。 给定两个这种链表&#xff0c;请生成代表两个整数相加值的结果链表。 例如&#xff1a;链表 1 为 9->3->7&#xff0c;链…

2021牛客暑期多校训练营8 J-Tree(思维dp+rmq)

J-Tree Cosmic_Tree题解 赛时队友想到了预处理s→ts\to ts→t路径上的点最远到达的点&#xff0c;后面贪心做的一直wa。正解是dp。 下面的solve(l,r,op)\text{solve}(l,r,\text{op})solve(l,r,op)函数中&#xff0c;当lrlrlr时不满足题意不合法&#xff0c;当op0\text{op}0op…

[翻译] ASP.NET Core 2.2 正式版发布

本文为翻译&#xff0c;原文地址&#xff1a;https://blogs.msdn.microsoft.com/webdev/2018/12/04/asp-net-core-2-2-available-today/我&#xff08;文章作者&#xff09;很高兴地宣布ASP.NET Core 2.2现在作为.NET Core 2.2的一部分提供&#xff01;怎么获取它您可以从 .NET…

理解至上:数位dp(ybtoj-B数计数)

文章目录简要题目描述解析dp定义:试填法代码thanks for reading&#xff01;简要 数位dp&#xff0c;天下第一 最重要的应该有两个&#xff1a; 1.状态转移式的确定 2.试填法不断往后模拟 &#xff08;至今是唯一一道数位dp&#xff0c;究竟重要的是啥我其实也没有太多经验 &am…

P7408-[JOI 2021 Final]ダンジョン 3【贪心,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P7408 题目大意 一个有n1n1n1层的地牢&#xff0c;从iii到i1i1i1层要AiA_iAi​点能量&#xff0c;第iii层可以花费BiB_iBi​获得111点能量。 mmm次询问从SiS_iSi​层出发到第TiT_iTi​层在能量上限为UiU_iUi​的情况下至少需…

牛客题霸 [输出二叉树的右视图] C++题解/答案

牛客题霸 [输出二叉树的右视图] C题解/答案 题目描述 请根据二叉树的前序遍历&#xff0c;中序遍历恢复二叉树&#xff0c;并打印出二叉树的右视图 题解&#xff1b; 分两个过程&#xff1a; 先用前序遍历中序遍历恢复二叉树&#xff0c;这个应该都会。。 打印二叉树的后视…

2021“MINIEYE杯”中国大学生算法设计超级联赛(10)Pty loves string(Border+二维数点)

Pty loves string 建立Border树后&#xff0c;发现可以转化成两个子树中相同点的数量&#xff0c;时间戳转化为连续的区间后相当于有两个数组&#xff0c;每次给两个区间&#xff0c;问区间相同点权的数目。 第一个数组作为区间&#xff0c;第二个数组作为权值。将第一个数组建…

微软推出了Cloud Native Application Bundles和开源ONNX Runtime

微软的Microsoft Connect(); 2018年的开发者大会 对Azure和IoT Edge服务进行了大量更新; Windows Presentation Foundation&#xff0c;Windows Forms和Windows UI XAML Library的开源 以及.NET 基金会会员模型的扩展。但那些只是冰山一角。微软还联合Docker发布了Cloud Native…

不止代码:友好城市(动态规划)

解析 先按左端点排序得到一个右端点的新队列&#xff0c;然后就可以发现&#xff1a; 所有合法的方案都是新队列的一个单调递增队列 然后就转化成了最长上升序列的问题 代码 #include<bits/stdc.h> using namespace std; const int N1e6100; int m,n; struct node{int…

二分图匹配(一)

文章目录什么是二分图&#xff1a;例题&#xff1a;NC111768 CF741C题目描述&#xff1a;题解&#xff1a;代码&#xff1a;二分图最大匹配匈牙利算法算法思想&#xff1a;代码&#xff1a;Knig定理二分图最优匹配KM(Kuhn-Munkres)算法算法思路&#xff1a;具体操作代码&#x…

P3980-[NOI2008]志愿者招募【费用流】

正题 题目链接:https://www.luogu.com.cn/problem/P3980 题目大意 nnn天&#xff0c;第iii天需要AiA_iAi​个志愿者。有mmm种志愿者&#xff0c;第iii种从sis_isi​天服务到tit_iti​天&#xff0c;需要cic_ici​元的费用。 求满足条件的最小费用 1≤n≤1000,1≤m≤100001\le…

不止代码:恐狼后卫(ybtoj-区间dp)

文章目录题目描述解析代码thanks for reading!题目描述 一代炉石的眼泪啊 解析 用dp[i][j]表示i与j之间的全部消掉&#xff08;不含两端&#xff09;的最小花费 然后枚举中间最后杀死的狼就行了 本题没有一次AC&#xff0c;因为一开始dp定义成了包含两端&#xff0c;然后因为…

牛客题霸 [二叉树的之字形层序遍历] C++题解/答案

牛客题霸 [二叉树的之字形层序遍历] C题解/答案 题目描述 给定一个二叉树&#xff0c;返回该二叉树的之字形层序遍历&#xff0c;&#xff08;第一层从左向右&#xff0c;下一层从右向左&#xff0c;一直这样交替&#xff09; 例如&#xff1a; 给定的二叉树是{3,9,20,#,#,15…