祗疼妳一个 发表于 2024-7-19 07:08:06

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

在这篇文章中,我们将探究如何在 ASP.NET WebForms 中实现IP拦截器,以便在 ASMX Web 服务方法 和 HTTP 请求 中根据IP地址举行访问控制。我们将使用自界说的 SoapExtension 和 IHttpModule 来实现这一功能,并根据常用的两种文本传输协议: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>
   
   
   
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
   
    public class Test : System.Web.Services.WebService
    {

      
      public string HelloWorld()
      {
            return "Hello World";
      }

      
      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 文件夹。
https://i-blog.csdnimg.cn/direct/e6955a2e6f214a1b94d10aed08d00e41.png
在 SOAP 文件夹里创建 IpFilterAttribute 类。
https://i-blog.csdnimg.cn/direct/036dfe0540444c0fa3d3d74791cd4df5.png
https://i-blog.csdnimg.cn/direct/b503bef2b53a47fb869386ae98b3b0f9.png
IpFilterAttribute.cs 代码如下:
using System;
using System.Web.Services.Protocols;

namespace TestAsmxProject.Filter.SOAP
{
   
    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
2. 创建基于SoapExtension的IpFilter注解类

创建 IpFilter.cs,继承 SoapExtension。
https://i-blog.csdnimg.cn/direct/46f477de14f64953a74ba3697f625f7f.png
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
3. 设置web.config中IP白名单

在 web.config 文件中设置白名单IP列表,在 IpFilter.cs 里我们已经写过该逻辑,web.config 文件中白名单内的 IpWhiteList 里的IP是全局白名单,无论 WebService服务方法 上是否有 注解。
<configuration>
<appSettings>
    <add key="IpWhiteList" value="127.0.0.1,192.168.1.1" />
</appSettings>
</configuration>
4. 在WebService方法上添加注解

在 WebService服务方法 上使用 注解,可以界说该方法的专属IP白名单(包含 web.config 中的全局白名单),如果不设定,则仅使用 web.config 中的白名单。
加了 注解后的 TestAsmxProject.Asmx 代码如下:
using System.Web.Services;
using TestAsmxProject.Filter.SOAP;

namespace TestAsmxProject.Asmx
{
    /// <summary>
    /// Test 的摘要说明
    /// </summary>
   
   
   
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
   
    public class Test : System.Web.Services.WebService
    {

      
       // 不传入指定IP,使用web.config中的白名单
      public string HelloWorld()
      {
            return "Hello World";
      }

      
       // 此处为该方法的IP白名单,加上web.config中的白名单共同生效
      public int Add(int a, int b)
      {
            return a + b;
      }

    }
}
https://i-blog.csdnimg.cn/direct/f0e8a0d36c5849ef8320e9b4886e87c1.png
三、基于HTTP协议的拦截器实现

接下来,我们创建一个基于HTTP协议的拦截器来实现IP拦截。同样,我们必要一个自界说属性来指定允许的IP地址。
1. 创建IpFilterAttribute类

新建 Filter 文件夹,再在 Filter 文件夹里新建 HTTP 文件夹。
https://i-blog.csdnimg.cn/direct/e6955a2e6f214a1b94d10aed08d00e41.png
在 SOAP 文件夹里创建 IpFilterAttribute 类。
https://i-blog.csdnimg.cn/direct/892c6f7aef4d45fb8a0cb8f10f67f537.png
https://i-blog.csdnimg.cn/direct/b503bef2b53a47fb869386ae98b3b0f9.png
IpFilterAttribute.cs 代码如下:
using System;
using System.Configuration;

namespace TestAsmxProject.Filter.HTTP
{
   
    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.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
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('/').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服务方法 上是否有 注解。
<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服务方法 上使用 注解,可以界说该方法的专属IP白名单(包含 web.config 中的全局白名单),如果不设定,则仅使用 web.config 中的白名单。
加了 注解后的 TestAsmxProject.Asmx 代码如下:
using System.Web.Services;
using TestAsmxProject.Filter.HTTP;

namespace TestAsmxProject.Asmx
{
    /// <summary>
    /// Test 的摘要说明
    /// </summary>
   
   
   
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
   
    public class Test : System.Web.Services.WebService
    {

      
       // 不传入指定IP,使用web.config中的白名单
      public string HelloWorld()
      {
            return "Hello World";
      }

      
       // 此处为该方法的IP白名单,加上web.config中的白名单共同生效
      public int Add(int a, int b)
      {
            return a + b;
      }

    }
}
https://i-blog.csdnimg.cn/direct/037993cb94274576a6db120d293843f2.png
四、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地址。通过将安全控制逻辑封装在自界说模块和扩展中,可以保持业务代码的简洁和可读性。
希望这篇文章对你在ASP.NET WebForms应用中的IP访问控制有所资助。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: C#进阶-基于.NET Framework 4.x框架实现ASP.NET WebForms项目IP拦截器