C#进阶-基于.NET Framework 4.x框架实现ASP.NET WebForms项目IP拦截器

devtools/2024/10/20 4:08:00/
http://www.w3.org/2000/svg" style="display: none;">

在这篇文章中,我们将探讨如何在 ASP.NET WebForms 中实现IP拦截器,以便在 ASMX Web 服务方法HTTP 请求 中根据IP地址进行访问控制。我们将使用自定义的 SoapExtensionIHttpModule 来实现这一功能,并根据常用的两种文本传输协议:SOAP协议HTTP协议进行分别讲解。


一、创建ASMX接口文件

首先,我们创建一个 ASP.NET WebForms 项目,创建 TestAsmxProject.Asmx 文件,并定义里面的 WebService 服务。
如果不会创建 ASMX 文件,可以参考我的上一篇文章:C#进阶-ASP.NET WebForms调用ASMX的WebService接口。

TestAsmxProject.Asmx 代码如下:

using System.Web.Services;namespace TestAsmxProject.Asmx
{/// <summary>/// Test 的摘要说明/// </summary>[WebService(Namespace = "http://tempuri.org/")][WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)][System.ComponentModel.ToolboxItem(false)]// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 [System.Web.Script.Services.ScriptService]public class Test : System.Web.Services.WebService{[WebMethod]public string HelloWorld(){return "Hello World";}[WebMethod(Description = "计算两个数的和")]public int Add(int a, int b){return a + b;}}
}

从这个类我们可以看到,目前是有两个 WebService 方法:HelloWorld 方法和 Add方法。调用 HelloWorld 方法会返回 "Hello World" 字符串;用 Add 方法,需要传入 ab 两个参数,会返回 ab 相加的和。


二、基于SOAP协议的拦截器实现

创建一个自定义的 SoapExtension 来实现IP拦截。我们还需要一个自定义属性来指定允许的IP地址。

1. 创建IpFilterAttribute类

新建 Filter 文件夹,再在 Filter 文件夹里新建 SOAP 文件夹。

https://i-blog.csdnimg.cn/direct/e6955a2e6f214a1b94d10aed08d00e41.png" alt="请添加图片描述" />

SOAP 文件夹里创建 IpFilterAttribute 类。

https://i-blog.csdnimg.cn/direct/036dfe0540444c0fa3d3d74791cd4df5.png" alt="在这里插入图片描述" />

https://i-blog.csdnimg.cn/direct/b503bef2b53a47fb869386ae98b3b0f9.png" alt="在这里插入图片描述" />

IpFilterAttribute.cs 代码如下:

using System;
using System.Web.Services.Protocols;namespace TestAsmxProject.Filter.SOAP
{[AttributeUsage(AttributeTargets.Method)]public class IpFilterAttribute : SoapExtensionAttribute{public override Type ExtensionType => typeof(IpFilter);public override int Priority { get; set; }public string[] AllowedIps { get; private set; }public IpFilterAttribute(params string[] ips){AllowedIps = ips.Length > 0 ? ips : null;Priority = 1;}} 
}

https://i-blog.csdnimg.cn/direct/8b431344738b44c2b70397be1e0203b3.png" alt="在这里插入图片描述" />


2. 创建基于SoapExtension的IpFilter注解类

创建 IpFilter.cs,继承 SoapExtension

https://i-blog.csdnimg.cn/direct/46f477de14f64953a74ba3697f625f7f.png" alt="在这里插入图片描述" />

IpFilter.cs 代码如下:

using System;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Services.Protocols;namespace TestAsmxProject.Filter.SOAP
{public class IpFilter : SoapExtension{private string[] allowedIps;public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute){var ipFilterAttribute = attribute as IpFilterAttribute;return ipFilterAttribute?.AllowedIps;}public override object GetInitializer(Type serviceType){return null;}public override void Initialize(object initializer){allowedIps = initializer as string[];}public override void ProcessMessage(SoapMessage message){switch (message.Stage){case SoapMessageStage.BeforeSerialize:break;case SoapMessageStage.AfterSerialize:break;case SoapMessageStage.BeforeDeserialize:CheckIpValidation(message);break;case SoapMessageStage.AfterDeserialize:break;}}private void CheckIpValidation(SoapMessage message){try{string clientIp = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];if (string.IsNullOrEmpty(clientIp)){clientIp = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];}if (!IsValidIp(clientIp)){HttpContext.Current.Response.Clear();HttpContext.Current.Response.StatusCode = 403;HttpContext.Current.Response.ContentType = "text/plain";HttpContext.Current.Response.Write("Access denied: Your IP address is not allowed.");HttpContext.Current.Response.End();}}catch (Exception ex){throw;}}private bool IsValidIp(string ip){string configIps = ConfigurationManager.AppSettings["IpWhiteList"];string[] configAllowedIps = !string.IsNullOrWhiteSpace(configIps)? configIps.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries): new string[] { };var allAllowedIps = (allowedIps == null ? new string[] { } : allowedIps).Concat(configAllowedIps).ToArray();return allAllowedIps.Any(allowIp => ip == allowIp);}}
}

https://i-blog.csdnimg.cn/direct/7a5c041285f54a7998646dfb87cc7660.png" alt="在这里插入图片描述" />


3. 配置web.config中IP白名单

web.config 文件中配置白名单IP列表,在 IpFilter.cs 里我们已经写过该逻辑,web.config 文件中白名单内的 IpWhiteList 里的IP是全局白名单,无论 WebService服务方法 上是否有 [IpFilter] 注解。

<configuration><appSettings><add key="IpWhiteList" value="127.0.0.1,192.168.1.1" /></appSettings>
</configuration>

4. 在WebService方法上添加注解

WebService服务方法 上使用 [IpFilter] 注解,可以定义该方法的专属IP白名单(包含 web.config 中的全局白名单),如果不设定,则仅使用 web.config 中的白名单。

加了 [IpFilter] 注解后的 TestAsmxProject.Asmx 代码如下:

using System.Web.Services;
using TestAsmxProject.Filter.SOAP;namespace TestAsmxProject.Asmx
{/// <summary>/// Test 的摘要说明/// </summary>[WebService(Namespace = "http://tempuri.org/")][WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)][System.ComponentModel.ToolboxItem(false)]// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 [System.Web.Script.Services.ScriptService]public class Test : System.Web.Services.WebService{[WebMethod][IpFilter] // 不传入指定IP,使用web.config中的白名单public string HelloWorld(){return "Hello World";}[WebMethod(Description = "计算两个数的和")][IpFilter("127.0.0.1", "192.168.1.1")] // 此处为该方法的IP白名单,加上web.config中的白名单共同生效public int Add(int a, int b){return a + b;}}
}

https://i-blog.csdnimg.cn/direct/f0e8a0d36c5849ef8320e9b4886e87c1.png" alt="在这里插入图片描述" />


三、基于HTTP协议的拦截器实现

接下来,我们创建一个基于HTTP协议的拦截器来实现IP拦截。同样,我们需要一个自定义属性来指定允许的IP地址。

1. 创建IpFilterAttribute类

新建 Filter 文件夹,再在 Filter 文件夹里新建 HTTP 文件夹。

https://i-blog.csdnimg.cn/direct/e6955a2e6f214a1b94d10aed08d00e41.png" alt="请添加图片描述" />

SOAP 文件夹里创建 IpFilterAttribute 类。

https://i-blog.csdnimg.cn/direct/892c6f7aef4d45fb8a0cb8f10f67f537.png" alt="在这里插入图片描述" />

https://i-blog.csdnimg.cn/direct/b503bef2b53a47fb869386ae98b3b0f9.png" alt="在这里插入图片描述" />

IpFilterAttribute.cs 代码如下:

using System;
using System.Configuration;namespace TestAsmxProject.Filter.HTTP
{[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]public sealed class IpFilterAttribute : Attribute{public string[] AllowedIps { get; private set; }public IpFilterAttribute(params string[] ips){string configIps = ConfigurationManager.AppSettings["IpWhiteList"];var configAllowedIps = !string.IsNullOrEmpty(configIps)? configIps.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries): new string[] { };AllowedIps = new string[ips.Length + configAllowedIps.Length];ips.CopyTo(AllowedIps, 0);configAllowedIps.CopyTo(AllowedIps, ips.Length);}public bool IsAllowedIp(string userIp){return AllowedIps.Any(ip => userIp == ip);}}
}

2. 创建基于IHttpModule的IpFilter注解类

创建 IpFilter.cs,继承 IHttpModule

https://i-blog.csdnimg.cn/direct/46f477de14f64953a74ba3697f625f7f.png" alt="在这里插入图片描述" />

IpFilter.cs 代码如下:

using System;
using System.Linq;
using System.Reflection;
using System.Web;namespace TestAsmxProject.Filter.HTTP
{public class IpFilter : IHttpModule{public void Init(HttpApplication context){context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute);}private void OnPreRequestHandlerExecute(object sender, EventArgs e){HttpApplication application = (HttpApplication)sender;HttpContext context = application.Context;if (context.Request.Path.Contains(".asmx")){string userIp = context.Request.UserHostAddress;string methodName = context.Request.PathInfo.Replace("/", "");Type webServiceType = GetWebServiceType(context.Request.Path);if (webServiceType != null){MethodInfo methodInfo = webServiceType.GetMethod(methodName);if (methodInfo != null){var attribute = methodInfo.GetCustomAttribute<IpFilterAttribute>();if (attribute != null && !attribute.IsAllowedIp(userIp)){context.Response.StatusCode = 403;context.Response.ContentType = "text/plain";context.Response.Write("Access denied: Your IP address is not allowed.");context.Response.End();}}}}}private Type GetWebServiceType(string path){string serviceName = path.Split('/')[2].Split('.').First();string namespacePrefix = "WebForms.CAS";string typeName = $"{namespacePrefix}.{serviceName}";Type serviceType = Type.GetType(typeName);if (serviceType == null){var assemblies = AppDomain.CurrentDomain.GetAssemblies();foreach (var assembly in assemblies){serviceType = assembly.GetType(typeName);if (serviceType != null){break;}}}return serviceType;}public void Dispose() { }}
}

3. 配置web.config中白名单和模块

web.config 文件中配置白名单IP列表,在 IpFilter.cs 里我们已经写过该逻辑,web.config 文件中白名单内的 IpWhiteList 里的IP是全局白名单,无论 WebService服务方法 上是否有 [IpFilter] 注解。

<configuration><appSettings><add key="IpWhiteList" value="127.0.0.1,192.168.1.1" /></appSettings><system.web><httpModules><add name="IpFilter" type="TestAsmxProject.Filter.HTTP.IpFilter"/></httpModules></system.web><system.webServer><validation validateIntegratedModeConfiguration="false" /><modules runAllManagedModulesForAllRequests="true"><add name="IpFilter" type="TestAsmxProject.Filter.HTTP.IpFilter"/></modules></system.webServer>
</configuration>

4. 在WebService方法上添加注解

WebService服务方法 上使用 [IpFilter] 注解,可以定义该方法的专属IP白名单(包含 web.config 中的全局白名单),如果不设定,则仅使用 web.config 中的白名单。

加了 [IpFilter] 注解后的 TestAsmxProject.Asmx 代码如下:

using System.Web.Services;
using TestAsmxProject.Filter.HTTP;namespace TestAsmxProject.Asmx
{/// <summary>/// Test 的摘要说明/// </summary>[WebService(Namespace = "http://tempuri.org/")][WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)][System.ComponentModel.ToolboxItem(false)]// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 [System.Web.Script.Services.ScriptService]public class Test : System.Web.Services.WebService{[WebMethod][IpFilter] // 不传入指定IP,使用web.config中的白名单public string HelloWorld(){return "Hello World";}[WebMethod(Description = "计算两个数的和")][IpFilter("127.0.0.1", "192.168.1.1")] // 此处为该方法的IP白名单,加上web.config中的白名单共同生效public int Add(int a, int b){return a + b;}}
}

https://i-blog.csdnimg.cn/direct/037993cb94274576a6db120d293843f2.png" alt="在这里插入图片描述" />


四、IP拦截器实现总结

通过上述步骤,我们成功实现了在 ASP.NET WebForms 中基于IP地址的访问控制。我们分别使用自定义的 SoapExtensionIHttpModule,实现了对ASMX Web服务方法和HTTP请求的IP拦截

1. 自定义 SoapExtension

自定义的 SoapExtension 通过重载 ProcessMessage 方法,在SOAP消息处理的不同阶段进行IP地址的验证。通过检查请求的IP地址并与允许的IP列表进行比较,我们可以在消息反序列化之前阻止不符合条件的请求,从而有效地控制对Web服务方法的访问。这种方法特别适用于基于SOAP的Web服务,能够在服务方法调用之前进行精细的访问控制。

2. 自定义 IHttpModule

自定义的 IHttpModule 通过实现 Init 方法并注册 PreRequestHandlerExecute 事件,在每个HTTP请求处理之前执行IP地址验证。通过反射获取请求对应的方法,并检查方法上的自定义属性 IpFilterAttribute,我们可以动态地对特定方法应用IP过滤规则。结合 web.config 中配置的白名单IP地址,这种方法能够灵活地扩展和维护IP访问控制规则,适用于一般的HTTP请求拦截需求。

3. 本文提供方法的实现优势

这种IP拦截器的实现方法不仅增强了应用程序的安全性,还具有良好的扩展性和可维护性。开发者可以根据具体需求,通过配置文件或代码注解灵活地管理允许的IP地址。通过将安全控制逻辑封装在自定义模块和扩展中,可以保持业务代码的简洁和可读性。

希望这篇文章对你在ASP.NET WebForms应用中的IP访问控制有所帮助。


http://www.ppmy.cn/devtools/59367.html

相关文章

Log4j的原理及应用详解(二)

本系列文章简介: 在软件开发的广阔领域中,日志记录是一项至关重要的活动。它不仅帮助开发者追踪程序的执行流程,还在问题排查、性能监控以及用户行为分析等方面发挥着不可替代的作用。随着软件系统的日益复杂,对日志管理的需求也日益增长,因此,一个高效、灵活且易于使用的…

【Flask从入门到精通:第十二课:常用模块、蓝图 Blueprint】

常用模块 Faker 文档: https://faker.readthedocs.io/en/master/locales/zh_CN.html 批量生成测试数据: https://github.com/joke2k/faker pip install faker -i https://pypi.douban.com/simple代码&#xff1a; from flask import Flask from flask_sqlalchemy import S…

面试题 29. 顺时针打印矩阵

顺时针打印矩阵 题目描述示例 题解 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 题解 从外往里一圈一圈遍历并…

昇思25天学习打卡营第六天|应用实践/计算机视觉/Vision Transformer图像分类

心得 运行模型似乎有点靠天意&#xff1f;每次跑模型之前先来个焚香沐浴&#xff1f;总之今天是机器视觉的最后一课了&#xff0c;尽管课程里强调模型跑得慢&#xff0c;可是我的这次运行&#xff0c;居然很快的就看到结果了。 如果一直看我这个系列文章的小伙伴&#xff0c;…

微服务治理新篇章:Eureka中细粒度策略管理实现

微服务治理新篇章&#xff1a;Eureka中细粒度策略管理实现 在微服务架构中&#xff0c;服务的治理和管理是确保系统稳定性和可扩展性的关键。Eureka作为Netflix开源的服务发现框架&#xff0c;提供了基本的服务注册与发现功能。然而&#xff0c;随着微服务规模的扩大和业务需求…

[Spring] Spring Web MVC案例实战

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

clion中建立c文件工程,读取或创建sqlite3数据库文件

1.首先前往SQLite官网下载sqlite3所需文件 SQLite Download Page 2.解压文件&#xff0c;将其中的sqlite3.c和sqlite3.h拷贝到你对应的文件工程中 3.修改CMakeLists.txt文件&#xff0c;添加编译选项及连接文件 4.运行代码及查询数据库文件

codeforce 954 div3 G2题

思路&#xff1a; 质因子分解可以顺着分解&#xff0c;也可以逆着分解 即找到每一个数字的倍数&#xff0c;再找到每一个数字的因数 const int N 5e510; vector<int> ff[N]; vector<int> f[N]; vector<int> g[N];void solve(){int n;cin>>n;vector&l…