From f973854d982bf2dbc45ac54947b83a4c04b75eb6 Mon Sep 17 00:00:00 2001 From: JianWeie Date: Fri, 20 May 2022 14:48:06 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=AE=A2=E6=88=B7=E7=AB=AFIP=E9=99=90=E6=B5=81?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppSettingsConstVars.cs | 6 +- .../Config/IpPolicyRateLimitSetup.cs | 42 ++++++++++++ CoreCms.Net.Core/CoreCms.Net.Core.csproj | 1 + .../CoreCms.Net.Middlewares.csproj | 4 ++ CoreCms.Net.Middlewares/IpLimitMiddleware.cs | 38 +++++++++++ CoreCms.Net.Web.Admin/Startup.cs | 4 ++ CoreCms.Net.Web.Admin/appsettings.json | 65 +++++++++++++++++++ CoreCms.Net.Web.WebApi/Startup.cs | 4 ++ CoreCms.Net.Web.WebApi/appsettings.json | 65 +++++++++++++++++++ 9 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 CoreCms.Net.Core/Config/IpPolicyRateLimitSetup.cs create mode 100644 CoreCms.Net.Middlewares/IpLimitMiddleware.cs diff --git a/CoreCms.Net.Configuration/AppSettingsConstVars.cs b/CoreCms.Net.Configuration/AppSettingsConstVars.cs index 1bcf6d87..0f315abb 100644 --- a/CoreCms.Net.Configuration/AppSettingsConstVars.cs +++ b/CoreCms.Net.Configuration/AppSettingsConstVars.cs @@ -81,10 +81,14 @@ namespace CoreCms.Net.Configuration #region Middleware中间件================================================================================ /// - /// Ip限流 + /// 是否记录ip信息 /// public static readonly bool MiddlewareIpLogEnabled = AppSettingsHelper.GetContent("Middleware", "IPLog", "Enabled").ObjToBool(); /// + /// 是否开启IP限流 + /// + public static readonly bool MiddlewareIpRateLimitEnabled = AppSettingsHelper.GetContent("Middleware", "IpRateLimit", "Enabled").ObjToBool(); + /// /// 记录请求与返回数据 /// public static readonly bool MiddlewareRequestResponseLogEnabled = AppSettingsHelper.GetContent("Middleware", "RequestResponseLog", "Enabled").ObjToBool(); diff --git a/CoreCms.Net.Core/Config/IpPolicyRateLimitSetup.cs b/CoreCms.Net.Core/Config/IpPolicyRateLimitSetup.cs new file mode 100644 index 00000000..9367748a --- /dev/null +++ b/CoreCms.Net.Core/Config/IpPolicyRateLimitSetup.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AspNetCoreRateLimit; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace CoreCms.Net.Core.Config +{ + /// + /// IPLimit限流 启动服务 + /// + public static class IpPolicyRateLimitSetup + { + public static void AddIpPolicyRateLimitSetup(this IServiceCollection services, IConfiguration Configuration) + { + if (services == null) throw new ArgumentNullException(nameof(services)); + + // 需要将限制规则存储到高速内存中 + services.AddMemoryCache(); + // 载入配置文件的规则设置 + services.Configure(Configuration.GetSection("IpRateLimiting")); + // 注入计数器和规则存储 + services.AddSingleton(); + services.AddSingleton(); + + // 注入计数器和规则分布式缓存存储(根据需求自行扩展) + //services.AddSingleton(); + //services.AddSingleton(); + + // 用于解析上下文的注入 + services.AddSingleton(); + // 配置(解析器、计数器密钥生成器) + services.AddSingleton(); + + services.AddSingleton(); + } + } +} diff --git a/CoreCms.Net.Core/CoreCms.Net.Core.csproj b/CoreCms.Net.Core/CoreCms.Net.Core.csproj index d65ff6a4..864dc521 100644 --- a/CoreCms.Net.Core/CoreCms.Net.Core.csproj +++ b/CoreCms.Net.Core/CoreCms.Net.Core.csproj @@ -11,6 +11,7 @@ + diff --git a/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj b/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj index 394ce2ef..aaa6fef4 100644 --- a/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj +++ b/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj @@ -4,6 +4,10 @@ net6.0 + + + + diff --git a/CoreCms.Net.Middlewares/IpLimitMiddleware.cs b/CoreCms.Net.Middlewares/IpLimitMiddleware.cs new file mode 100644 index 00000000..520c3dd7 --- /dev/null +++ b/CoreCms.Net.Middlewares/IpLimitMiddleware.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AspNetCoreRateLimit; +using CoreCms.Net.Configuration; +using CoreCms.Net.Loging; +using Hangfire.Logging; +using Microsoft.AspNetCore.Builder; +using NLog; +using LogLevel = NLog.LogLevel; + +namespace CoreCms.Net.Middlewares +{ + /// + /// 限制 ip 流量 + /// + public static class IpLimitMiddleware + { + public static void UseIpLimitMiddle(this IApplicationBuilder app) + { + if (app == null) throw new ArgumentNullException(nameof(app)); + try + { + if (AppSettingsConstVars.MiddlewareIpRateLimitEnabled) + { + app.UseIpRateLimiting(); + } + } + catch (Exception e) + { + NLogUtil.WriteFileLog(LogLevel.Error, LogType.ApiRequest, "全局捕获异常", "限制ip流量异常", e); + throw; + } + } + } +} diff --git a/CoreCms.Net.Web.Admin/Startup.cs b/CoreCms.Net.Web.Admin/Startup.cs index b6138e72..eb82a85b 100644 --- a/CoreCms.Net.Web.Admin/Startup.cs +++ b/CoreCms.Net.Web.Admin/Startup.cs @@ -99,6 +99,8 @@ namespace CoreCms.Net.Web.Admin services.AddHttpClient(); services.AddSingleton(); + //ÿͻIP + services.AddIpPolicyRateLimitSetup(Configuration); //Swaggerӿĵע services.AddAdminSwaggerSetup(); @@ -171,6 +173,8 @@ namespace CoreCms.Net.Web.Admin /// public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + // Ip + app.UseIpLimitMiddle(); // ¼뷵 (ע⿪ȨޣȻ޷д) app.UseRequestResponseLog(); // ûʼ¼(ŵ㣬Ȼ쳣ᱨΪܷ)(ע⿪ȨޣȻ޷д) diff --git a/CoreCms.Net.Web.Admin/appsettings.json b/CoreCms.Net.Web.Admin/appsettings.json index 4ea5d0dc..f6ee5a83 100644 --- a/CoreCms.Net.Web.Admin/appsettings.json +++ b/CoreCms.Net.Web.Admin/appsettings.json @@ -54,8 +54,73 @@ //记录IP请求数据 "IPLog": { "Enabled": false + }, + //开启Ip限流 + "IpRateLimit": { + "Enabled": false } }, + //ip限流规则设置 + "IpRateLimiting": { + //如果EnableEndpointRateLimiting设置为false,则限制将在全局范围内应用,并且仅适用于端点的规则*。例如,如果您设置每秒 5 次调用的限制,则对任何端点的任何 HTTP 调用都将计入该限制。 + //如果EnableEndpointRateLimiting设置为true,则限制将适用于每个端点,如{HTTP_Verb}{PATH}。例如,如果您为*:/api/values客户端设置每秒调用 5 次的限制,则每秒可以调用GET /api/values5 次,但也可以调用 5 次PUT /api/values。 + "EnableEndpointRateLimiting": false, + //如果StackBlockedRequests设置为false,则拒绝的呼叫不会添加到节流计数器。如果客户端每秒发出 3 个请求,并且您设置了每秒一个呼叫的限制,则其他限制(例如每分钟或每天计数器)将仅记录第一个呼叫,即未被阻止的呼叫。如果您希望被拒绝的请求计入其他限制,您必须设置StackBlockedRequests为true. + "StackBlockedRequests": false, + //用于在您的RealIpHeaderKestrel 服务器位于反向代理之后时提取客户端 IP,如果您的代理使用不同的标头,则X-Real-IP使用此选项进行设置。 + "RealIpHeader": "X-Real-IP", + //ClientIdHeader用于提取白名单的客户端 ID 。如果此标头中存在客户端 ID 并且与 ClientWhitelist 中指定的值匹配,则不应用速率限制。 + "ClientIdHeader": "X-ClientId", + //IP白名单:支持Ip v4和v6;如 //"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ], + "IpWhitelist": [], + //端点白名单 + "EndpointWhitelist": [ "get:/api/license", "*:/api/status" ], + //客户端白名单 + "ClientWhitelist": [ "dev-client-1", "dev-client-2" ], + "QuotaExceededResponse": { + "Content": "{{\"status\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"success\":false}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + //返回状态码 + "HttpStatusCode": 429, + //通用规则 + //api规则,结尾一定要带* + "GeneralRules": [ + //{ + // //端点路径 + // "Endpoint": "*:/api/*", + // //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + // "Period": "1m", + // //限制数量 + // "Limit": 60 + //}, + //1秒钟只能调用3次 + { + "Endpoint": "*", + "Period": "1s", + "Limit": 30 + }, + //1分钟只能调用300次 + { + "Endpoint": "*", + "Period": "1m", + "Limit": 1000 + }, + //12H只能调用10000 + { + "Endpoint": "*", + "Period": "12h", + "Limit": 100000 + }, + //7天只能调用100000次 + { + "Endpoint": "*", + "Period": "7d", + "Limit": 1000000 + } + ] + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/CoreCms.Net.Web.WebApi/Startup.cs b/CoreCms.Net.Web.WebApi/Startup.cs index c6268658..07e3dba5 100644 --- a/CoreCms.Net.Web.WebApi/Startup.cs +++ b/CoreCms.Net.Web.WebApi/Startup.cs @@ -109,6 +109,8 @@ namespace CoreCms.Net.Web.WebApi services.AddHttpClient(); services.AddSingleton(); + //ÿͻIP + services.AddIpPolicyRateLimitSetup(Configuration); //Swaggerӿĵע services.AddClientSwaggerSetup(); @@ -178,6 +180,8 @@ namespace CoreCms.Net.Web.WebApi /// public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + // Ip + app.UseIpLimitMiddle(); // ¼뷵 (ע⿪ȨޣȻ޷д) app.UseRequestResponseLog(); // ûʼ¼(ŵ㣬Ȼ쳣ᱨΪܷ)(ע⿪ȨޣȻ޷д) diff --git a/CoreCms.Net.Web.WebApi/appsettings.json b/CoreCms.Net.Web.WebApi/appsettings.json index 0f74175b..4db3cf5b 100644 --- a/CoreCms.Net.Web.WebApi/appsettings.json +++ b/CoreCms.Net.Web.WebApi/appsettings.json @@ -54,8 +54,73 @@ //记录IP请求数据 "IPLog": { "Enabled": false + }, + //开启Ip限流 + "IpRateLimit": { + "Enabled": false } }, + //ip限流规则设置 + "IpRateLimiting": { + //如果EnableEndpointRateLimiting设置为false,则限制将在全局范围内应用,并且仅适用于端点的规则*。例如,如果您设置每秒 5 次调用的限制,则对任何端点的任何 HTTP 调用都将计入该限制。 + //如果EnableEndpointRateLimiting设置为true,则限制将适用于每个端点,如{HTTP_Verb}{PATH}。例如,如果您为*:/api/values客户端设置每秒调用 5 次的限制,则每秒可以调用GET /api/values5 次,但也可以调用 5 次PUT /api/values。 + "EnableEndpointRateLimiting": false, + //如果StackBlockedRequests设置为false,则拒绝的呼叫不会添加到节流计数器。如果客户端每秒发出 3 个请求,并且您设置了每秒一个呼叫的限制,则其他限制(例如每分钟或每天计数器)将仅记录第一个呼叫,即未被阻止的呼叫。如果您希望被拒绝的请求计入其他限制,您必须设置StackBlockedRequests为true. + "StackBlockedRequests": false, + //用于在您的RealIpHeaderKestrel 服务器位于反向代理之后时提取客户端 IP,如果您的代理使用不同的标头,则X-Real-IP使用此选项进行设置。 + "RealIpHeader": "X-Real-IP", + //ClientIdHeader用于提取白名单的客户端 ID 。如果此标头中存在客户端 ID 并且与 ClientWhitelist 中指定的值匹配,则不应用速率限制。 + "ClientIdHeader": "X-ClientId", + //IP白名单:支持Ip v4和v6;如 //"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ], + "IpWhitelist": [], + //端点白名单 + "EndpointWhitelist": [ "get:/api/license", "*:/api/status" ], + //客户端白名单 + "ClientWhitelist": [ "dev-client-1", "dev-client-2" ], + "QuotaExceededResponse": { + "Content": "{{\"status\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"success\":false}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + //返回状态码 + "HttpStatusCode": 429, + //通用规则 + //api规则,结尾一定要带* + "GeneralRules": [ + //{ + // //端点路径 + // "Endpoint": "*:/api/*", + // //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + // "Period": "1m", + // //限制数量 + // "Limit": 60 + //}, + //1秒钟只能调用3次 + { + "Endpoint": "*", + "Period": "1s", + "Limit": 30 + }, + //1分钟只能调用300次 + { + "Endpoint": "*", + "Period": "1m", + "Limit": 1000 + }, + //12H只能调用10000 + { + "Endpoint": "*", + "Period": "12h", + "Limit": 100000 + }, + //7天只能调用100000次 + { + "Endpoint": "*", + "Period": "7d", + "Limit": 1000000 + } + ] + }, "Logging": { "LogLevel": { "Default": "Information",