zoukankan      html  css  js  c++  java
  • 如何为ASP.NET Core设置客户端IP白名单验证

    原文链接:Client IP safelist for ASP.NET Core
    作者:Damien Bowden and Tom Dykstra
    译者:Lamond Lu

    本篇博文中展示了如何在ASP.NET Core应用程序中设置IP白名单验证的3种方式。

    你可以使用一下3种方式:

    • 使用中间件检查每个请求的远程IP地址
    • 使用Action过滤器为指定的Controller或action方法添加针对远程IP地址的检查
    • 使用IPageFilter为Razor Pages应用添加针对远程IP地址的检查

    查看项目源代码

    白名单

    这里为了简化代码,我们将IP白名单列表放置在配置文件appSettings.json中,每个IP之间使用分号分隔。

    正式项目中,可以将这个列表保存在数据库中,便于管理

    {
      "AdminSafeList": "127.0.0.1;192.168.1.5;::1",
      "Logging": {
        "IncludeScopes": false,
        "LogLevel": {
          "Default": "Debug",
          "System": "Information",
          "Microsoft": "Information"
        }
      }
    }
    

    使用中间件检查每个请求的远程IP地址

    这里我们首先添加一个中间件AdminSafeListMiddleware

    public class AdminSafeListMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<AdminSafeListMiddleware> _logger;
        private readonly string _adminSafeList;
    
        public AdminSafeListMiddleware(
            RequestDelegate next, 
            ILogger<AdminSafeListMiddleware> logger, 
            string adminSafeList)
        {
            _adminSafeList = adminSafeList;
            _next = next;
            _logger = logger;
        }
    
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Method != "GET")
            {
                var remoteIp = context.Connection.RemoteIpAddress;
                _logger.LogDebug($"Request from Remote IP address: {remoteIp}");
    
                string[] ip = _adminSafeList.Split(';');
    
                var bytes = remoteIp.GetAddressBytes();
                var badIp = true;
                foreach (var address in ip)
                {
                    var testIp = IPAddress.Parse(address);
                    if(testIp.GetAddressBytes().SequenceEqual(bytes))
                    {
                        badIp = false;
                        break;
                    }
                }
    
                if(badIp)
                {
                    _logger.LogInformation(
                        $"Forbidden Request from Remote IP address: {remoteIp}");
                    context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                    return;
                }
            }
    
            await _next.Invoke(context);
    
        }
    }
    

    代码解释:

    • 这里在AdminSafeListMiddleware的构造函数中,我们传入了从配置文件中读取的IP白名单列表
    • 当请求进入当前中间件时,我们使用当前请求上下文的context.Connection.RemoteIpAddress获取到了客户端的IP
    • 如果客户端IP存在于IP白名单列表中,就运行下一个中间件,否则就直接返回401状态码。
    • 这里源代码中,只过滤了非GET请求,如果针对GET请求也需要启动IP白名单,可以去掉这个判断。

    然后我们需要在Startup.cs文件的Configure方法中将中间件添加到ASP.NET Core的中间件管道中。

    public void Configure(
        IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory)
    {
        loggerFactory.AddNLog();
    
        app.UseStaticFiles();
    
        app.UseMiddleware<AdminSafeListMiddleware>(
            Configuration["AdminSafeList"]);
        app.UseMvc();
    }
    

    注意: 这里我们在注册中间件的时候,传入了从配置文件中读取的IP白名单。

    使用Action过滤器

    如果你只是希望为某些特性的Controller或Action方法添加IP白名单,你可以使用Action过滤器。

    这里我们首先添加一个新类ClientIdCheckFilter, 它继承自ActionFilterAttribute

     public class ClientIdCheckFilter : ActionFilterAttribute
        {
            private readonly ILogger _logger;
            private readonly string _safelist;
    
            public ClientIdCheckFilter
                (ILoggerFactory loggerFactory, IConfiguration configuration)
            {
                _logger = loggerFactory.CreateLogger("ClientIdCheckFilter");
                _safelist = configuration["AdminSafeList"];
            }
    
            public override void OnActionExecuting(ActionExecutingContext context)
            {
                _logger.LogInformation(
                    $"Remote IpAddress: {context.HttpContext.Connection.RemoteIpAddress}");
    
                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
                _logger.LogDebug($"Request from Remote IP address: {remoteIp}");
    
                string[] ip = _safelist.Split(';');
    
                var bytes = remoteIp.GetAddressBytes();
                var badIp = true;
                foreach (var address in ip)
                {
                    var testIp = IPAddress.Parse(address);
                    if (testIp.GetAddressBytes().SequenceEqual(bytes))
                    {
                        badIp = false;
                        break;
                    }
                }
    
                if (badIp)
                {
                    _logger.LogInformation(
                        $"Forbidden Request from Remote IP address: {remoteIp}");
                    context.Result = new StatusCodeResult(401);
                    return;
                }
    
                base.OnActionExecuting(context);
            }
        }
    

    这里代码逻辑和前面中间的基本一样,主要的区别是

    • 这里我们是从IP白名单,我们是从IConfiguration对象中手动获取的
    • 这里我们复写了OnActionExecuting方法,如果当前客户端 IP存在于白名单中,我们就调用基类OnActionExecuting方法,执行当前Action请求,否则就返回一个401状态码
    • 这里没有针对请求类型的判断,所以指定当前过滤器的Action,GET请求也会受到白名单的限制

    第二步,我们需要将这action过滤器添加到服务容器中。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<ClientIdCheckFilter>();
    
        services.AddMvc(options =>
        {
            options.Filters.Add
                (new ClientIdCheckPageFilter
                    (_loggerFactory, Configuration));
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }
    

    第三步,我们可以在Action方法声明处添加ServiceFilter特性,传入的参数是我们之前定义好的ClientIdCheckFilter

    例:

    [ServiceFilter(typeof(ClientIdCheckFilter))]
    [HttpGet]
    public IEnumerable<string> Get()
    

    使用IPageFilter

    Razor Pages应用是ASP.NET Core 2.0中新引入的功能,它是ASP.NET Core Mvc的一个子集。

    如果希望Razor Pages应用支持IP白名单,我们需要创建一个新类ClientIdCheckPageFilter, 它实现了IPageFilter接口.

    public class ClientIdCheckPageFilter : IPageFilter
        {
            private readonly ILogger _logger;
            private readonly string _safelist;
    
            public ClientIdCheckPageFilter
                (ILoggerFactory loggerFactory, IConfiguration configuration)
            {
                _logger = loggerFactory.CreateLogger("ClientIdCheckPageFilter");
                _safelist = configuration["AdminSafeList"];
            }
    
            public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
            {
                _logger.LogInformation(
                    $"Remote IpAddress: {context.HttpContext.Connection.RemoteIpAddress}");
    
                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
                _logger.LogDebug($"Request from Remote IP address: {remoteIp}");
    
                string[] ip = _safelist.Split(';');
    
                var bytes = remoteIp.GetAddressBytes();
                var badIp = true;
                foreach (var address in ip)
                {
                    var testIp = IPAddress.Parse(address);
                    if (testIp.GetAddressBytes().SequenceEqual(bytes))
                    {
                        badIp = false;
                        break;
                    }
                }
    
                if (badIp)
                {
                    _logger.LogInformation(
                        $"Forbidden Request from Remote IP address: {remoteIp}");
                    context.Result = new StatusCodeResult(401);
                    return;
                }
            }
    
            public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
            {
            }
    
            public void OnPageHandlerSelected(PageHandlerSelectedContext context)
            {
            }
        }
    

    这里的代码实现和IActionFilter的实现基本一样,唯一的区别是代码放在了OnPageHandlerExecuting的实现中。

    第二步,我们还是需要将ClientIdCheckPageFilter添加到MVC的过滤器集合中。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<ClientIdCheckFilter>();
    
        services.AddMvc(options =>
        {
            options.Filters.Add
                (new ClientIdCheckPageFilter
                    (_loggerFactory, Configuration));
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }
    

    总结

    本篇我们讲解了在ASP.NET Core中启用IP白名单验证的3种方式

    • 使用中间件检查每个请求的远程IP地址
    • 使用Action过滤器为指定的Controller或action方法添加针对远程IP地址的检查
    • 使用IPageFilter为Razor Pages应用添加针对远程IP地址的检查
  • 相关阅读:
    volatile关键字
    const关键字祥解
    extern关键字祥解
    gcc和g++使用澄清
    [APIO2014]连珠线
    点名
    四轮车
    盘子序列
    序列问题
    长途旅行
  • 原文地址:https://www.cnblogs.com/lwqlun/p/10394688.html
Copyright © 2011-2022 走看看