跳到主要内容
C#进阶:基于.NET Framework 4.x 实现 ASP.NET WebForms IP 拦截器 | 极客日志
C#
C#进阶:基于.NET Framework 4.x 实现 ASP.NET WebForms IP 拦截器 在 ASP.NET WebForms 项目中实现 IP 地址访问控制的方法。通过自定义 SoapExtension 处理 SOAP 协议请求,以及使用 IHttpModule 处理 HTTP 协议请求,结合 web.config 配置白名单和代码注解,实现对 ASMX Web 服务方法的 IP 拦截。该方法增强了应用安全性,支持全局与方法级白名单配置。
本文将探讨如何在 ASP.NET WebForms 中实现 IP 拦截器,以便在 ASMX Web 服务方法和 HTTP 请求中根据 IP 地址进行访问控制。我们将使用自定义的 SoapExtension 和 IHttpModule 来实现这一功能,并根据常用的两种文本传输协议:SOAP 协议和 HTTP 协议分别讲解。
一、创建 ASMX 接口文件
首先,我们创建一个 ASP.NET WebForms 项目,创建 TestAsmxProject.Asmx 文件,并定义里面的 WebService 服务。
TestAsmxProject.Asmx 代码如下:
using System.Web.Services;
namespace TestAsmxProject.Asmx
{
[WebService(Namespace = "http://tempuri.org/" ) ]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1) ]
[System.ComponentModel.ToolboxItem(false) ]
[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 方法,需要传入 a 和 b 两个参数,会返回 a 和 b 相加的和。
二、基于 SOAP 协议的拦截器实现 创建一个自定义的 SoapExtension 来实现 IP 拦截。我们还需要一个自定义属性来指定允许的 IP 地址。
1. 创建 IpFilterAttribute 类 新建 Filter 文件夹,再在 Filter 文件夹里新建 SOAP 文件夹。
在 SOAP 文件夹里创建 IpFilterAttribute 类。
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 ;
}
}
}
2. 创建基于 SoapExtension 的 IpFilter 注解类 创建 IpFilter.cs,继承 SoapExtension。
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);
}
}
}
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
{
[WebService(Namespace = "http://tempuri.org/" ) ]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1) ]
[System.ComponentModel.ToolboxItem(false) ]
[System.Web.Script.Services.ScriptService ]
public class Test : System.Web.Services.WebService
{
[WebMethod ]
[IpFilter ]
public string HelloWorld ()
{
return "Hello World" ;
}
[WebMethod(Description = "计算两个数的和" ) ]
[IpFilter("127.0.0.1" , "192.168.1.1" ) ]
public int Add (int a, int b )
{
return a + b;
}
}
}
三、基于 HTTP 协议的拦截器实现 接下来,我们创建一个基于 HTTP 协议的拦截器来实现 IP 拦截。同样,我们需要一个自定义属性来指定允许的 IP 地址。
1. 创建 IpFilterAttribute 类 新建 Filter 文件夹,再在 Filter 文件夹里新建 HTTP 文件夹。
在 HTTP 文件夹里创建 IpFilterAttribute 类。
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。
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 = "" ;
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
{
[WebService(Namespace = "http://tempuri.org/" ) ]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1) ]
[System.ComponentModel.ToolboxItem(false) ]
[System.Web.Script.Services.ScriptService ]
public class Test : System.Web.Services.WebService
{
[WebMethod ]
[IpFilter ]
public string HelloWorld ()
{
return "Hello World" ;
}
[WebMethod(Description = "计算两个数的和" ) ]
[IpFilter("127.0.0.1" , "192.168.1.1" ) ]
public int Add (int a, int b )
{
return a + b;
}
}
}
四、IP 拦截器实现总结 通过上述步骤,我们成功实现了在 ASP.NET WebForms 中基于 IP 地址的访问控制。我们分别使用自定义的 SoapExtension 和 IHttpModule,实现了对 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 地址。通过将安全控制逻辑封装在自定义模块和扩展中,可以保持业务代码的简洁和可读性。
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online