zuohuaijun 4 лет назад
Родитель
Сommit
8b528414a7

+ 5 - 0
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -10,15 +10,20 @@
   <ItemGroup>
     <None Remove="Admin.NET.Core.xml" />
     <None Remove="AdminNETConfig.json" />
+    <None Remove="RateLimitConfig.json" />
   </ItemGroup>
 
   <ItemGroup>
     <Content Include="AdminNETConfig.json">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="RateLimitConfig.json">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
   </ItemGroup>
 
   <ItemGroup>
+    <PackageReference Include="AspNetCoreRateLimit" Version="4.0.2" />
     <PackageReference Include="Caching.CSRedis" Version="3.8.3" />
     <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.0.3" />
     <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.0.3" />

+ 22 - 3
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -2906,6 +2906,26 @@
             支付宝退款回调
             </summary>
         </member>
+        <member name="T:Admin.NET.Core.IpRateLimitingOptions">
+            <summary>
+            IP限流配置选项
+            </summary>
+        </member>
+        <member name="T:Admin.NET.Core.IpRateLimitPoliciesOptions">
+            <summary>
+            IP限流策略配置选项
+            </summary>
+        </member>
+        <member name="T:Admin.NET.Core.ClientRateLimitingOptions">
+            <summary>
+            客户端限流配置选项
+            </summary>
+        </member>
+        <member name="T:Admin.NET.Core.ClientRateLimitPoliciesOptions">
+            <summary>
+            客户端限流策略配置选项
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.RefreshTokenOptions">
             <summary>
             刷新Token配置选项
@@ -6590,12 +6610,11 @@
             </summary>
             <typeparam name="T"></typeparam>
         </member>
-        <member name="M:Admin.NET.Core.SqlSugarSetup.AddSqlSugarSetup(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration)">
+        <member name="M:Admin.NET.Core.SqlSugarSetup.AddSqlSugarSetup(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
             <summary>
-            Sqlsugar上下文初始化
+            Sqlsugar 上下文初始化
             </summary>
             <param name="services"></param>
-            <param name="configuration"></param>
         </member>
         <member name="M:Admin.NET.Core.SqlSugarSetup.InitDataBase(SqlSugar.SqlSugarScope,Admin.NET.Core.DbConnectionOptions)">
             <summary>

+ 35 - 0
Admin.NET/Admin.NET.Core/Option/RateLimitOptions.cs

@@ -0,0 +1,35 @@
+using AspNetCoreRateLimit;
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// IP限流配置选项
+/// </summary>
+public sealed class IpRateLimitingOptions : IpRateLimitOptions
+{
+
+}
+
+/// <summary>
+/// IP限流策略配置选项
+/// </summary>
+public sealed class IpRateLimitPoliciesOptions : IpRateLimitPolicies, IConfigurableOptions
+{
+
+}
+
+/// <summary>
+/// 客户端限流配置选项
+/// </summary>
+public sealed class ClientRateLimitingOptions : ClientRateLimitOptions, IConfigurableOptions
+{
+
+}
+
+/// <summary>
+/// 客户端限流策略配置选项
+/// </summary>
+public sealed class ClientRateLimitPoliciesOptions : ClientRateLimitPolicies, IConfigurableOptions
+{
+
+}

+ 119 - 0
Admin.NET/Admin.NET.Core/RateLimitConfig.json

@@ -0,0 +1,119 @@
+{
+  // IP限流配置
+  "IpRateLimiting": {
+    // 例如设置了5次每分钟访问限流
+    // 当False时:每个接口都加入计数,不管你访问哪个接口,只要在一分钟内累计够5次,将禁止访问。
+    // 当True 时:当一分钟请求了5次GetData接口,则该接口将在时间段内禁止访问,但是还可以访问PostData()5次,总得来说是每个接口都有5次在这一分钟,互不干扰。
+    "EnableEndpointRateLimiting": true,
+    // 如果StackBlockedRequests设置为false,拒绝的API调用不会添加到调用次数计数器上。比如:如果客户端每秒发出3个请求并且您设置了每秒一个调用的限制,
+    // 则每分钟或每天计数器等其他限制将仅记录第一个调用,即成功的API调用。如果您希望被拒绝的API调用计入其他时间的显示(分钟,小时等),则必须设置
+    "StackBlockedRequests": false,
+    // 在RealIpHeader使用时,你的Kestrel服务器背后是一个反向代理,如果你的代理服务器使用不同的页眉然后提取客户端IP X-Real-IP使用此选项来设置它。
+    "RealIpHeader": "X-Real-IP",
+    // 将ClientIdHeader被用于提取白名单的客户端ID。如果此标头中存在客户端ID并且与ClientWhitelist中指定的值匹配,则不应用速率限制。
+    "ClientIdHeader": "X-ClientId",
+    // IP白名单:支持Ip v4和v6
+    "IpWhitelist": [],
+    // 端点白名单
+    "EndpointWhitelist": [],
+    // 客户端白名单
+    "ClientWhitelist": [],
+    "QuotaExceededResponse": {
+      "Content": "{{\"code\":429,\"type\":\"error\",\"message\":\"访问过于频繁,请稍后重试!\",\"result\":null,\"extras\":null}}",
+      "ContentType": "application/json",
+      "StatusCode": 429
+    },
+    // 返回状态码
+    "HttpStatusCode": 429,
+    // API规则,结尾一定要带*
+    "GeneralRules": [
+      // 1秒钟只能调用1次
+      {
+        "Endpoint": "*",
+        "Period": "1s",
+        "Limit": 1
+      },
+      // 1分钟只能调用100次
+      {
+        "Endpoint": "*",
+        "Period": "1m",
+        "Limit": 100
+      },
+      // 1小时只能调用1000
+      {
+        "Endpoint": "*",
+        "Period": "1h",
+        "Limit": 1000
+      },
+      // 1天只能调用10000次
+      {
+        "Endpoint": "*",
+        "Period": "1d",
+        "Limit": 10000
+      }
+    ]
+  },
+  "IpRateLimitPolicies": {
+    "IpRules": [
+      {
+        "Ip": "XXX.XXX.XXX.XXX",
+        "Rules": [
+          {
+            "Endpoint": "*",
+            "Period": "1s",
+            "Limit": 1
+          },
+          {
+            "Endpoint": "*",
+            "Period": "1m",
+            "Limit": 100
+          }
+        ]
+      }
+    ]
+  },
+  // 客户端限流配置
+  "ClientRateLimiting": {
+    "EnableEndpointRateLimiting": true,
+    "ClientIdHeader": "X-ClientId",
+    "EndpointWhitelist": [],
+    "ClientWhitelist": [],
+    "QuotaExceededResponse": {
+      "Content": "{{\"code\":429,\"type\":\"error\",\"message\":\"访问人数过多,请稍后重试!\",\"result\":null,\"extras\":null}}",
+      "ContentType": "application/json",
+      "StatusCode": 429
+    },
+    "HttpStatusCode": 429,
+    "GeneralRules": [
+      {
+        "Endpoint": "*",
+        "Period": "1s",
+        "Limit": 1
+      },
+      {
+        "Endpoint": "*",
+        "Period": "1m",
+        "Limit": 100
+      }
+    ]
+  },
+  "ClientRateLimitPolicies": {
+    "ClientRules": [
+      {
+        "ClientId": "xxx-xxx",
+        "Rules": [
+          {
+            "Endpoint": "*",
+            "Period": "1s",
+            "Limit": 1
+          },
+          {
+            "Endpoint": "*",
+            "Period": "1m",
+            "Limit": 100
+          }
+        ]
+      }
+    ]
+  }
+}

+ 2 - 3
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -5,11 +5,10 @@ namespace Admin.NET.Core;
 public static class SqlSugarSetup
 {
     /// <summary>
-    /// Sqlsugar上下文初始化
+    /// Sqlsugar 上下文初始化
     /// </summary>
     /// <param name="services"></param>
-    /// <param name="configuration"></param>
-    public static void AddSqlSugarSetup(this IServiceCollection services, IConfiguration configuration)
+    public static void AddSqlSugarSetup(this IServiceCollection services)
     {
         var dbOptions = App.GetOptions<DbConnectionOptions>();
         var configureExternalServices = new ConfigureExternalServices

+ 3 - 0
Admin.NET/Admin.NET.Core/Util/BasePageInput.cs

@@ -8,11 +8,14 @@ public class BasePageInput
     /// <summary>
     /// 当前页码
     /// </summary>
+    [DataValidation(ValidationTypes.Numeric)]
     public virtual int Page { get; set; }
 
     /// <summary>
     /// 页码容量
     /// </summary>
+    [Range(1, 100, ErrorMessage = "页码容量超过最大限制")]
+    [DataValidation(ValidationTypes.Numeric)]
     public virtual int PageSize { get; set; }
 
     /// <summary>

+ 10 - 0
Admin.NET/Admin.NET.Web.Core/ProjectOptions.cs

@@ -1,4 +1,6 @@
 using Admin.NET.Core;
+using AspNetCoreRateLimit;
+using Furion;
 using Microsoft.Extensions.DependencyInjection;
 
 namespace Admin.NET.Web.Core;
@@ -23,6 +25,14 @@ public static class ProjectOptions
         services.AddConfigurableOptions<PayCallBackOptions>();
         services.AddConfigurableOptions<CodeGenOptions>();
         services.AddConfigurableOptions<EmailOptions>();
+        //services.AddConfigurableOptions<IpRateLimitingOptions>();
+        //services.AddConfigurableOptions<IpRateLimitPoliciesOptions>();
+        //services.AddConfigurableOptions<ClientRateLimitingOptions>();
+        //services.AddConfigurableOptions<ClientRateLimitPoliciesOptions>();
+        services.Configure<IpRateLimitOptions>(App.Configuration.GetSection("IpRateLimiting"));
+        services.Configure<IpRateLimitPolicies>(App.Configuration.GetSection("IpRateLimitPolicies"));
+        services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting"));
+        services.Configure<ClientRateLimitPolicies>(App.Configuration.GetSection("ClientRateLimitPolicies"));
 
         return services;
     }

+ 10 - 1
Admin.NET/Admin.NET.Web.Core/Startup.cs

@@ -1,4 +1,5 @@
 using Admin.NET.Core;
+using AspNetCoreRateLimit;
 using Furion;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
@@ -21,7 +22,7 @@ public class Startup : AppStartup
         // 配置选项
         services.AddProjectOptions();
         // ORM-SqlSugar
-        services.AddSqlSugarSetup(App.Configuration);
+        services.AddSqlSugarSetup();
         // JWT
         services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);
         // 允许跨域
@@ -48,6 +49,10 @@ public class Startup : AppStartup
             })
             .AddInjectWithUnifyResult<AdminResultProvider>();
 
+        // 限流服务
+        services.AddInMemoryRateLimiting();
+        services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
+
         // 事件总线
         services.AddEventBus(builder =>
         {
@@ -132,6 +137,10 @@ public class Startup : AppStartup
 
         app.UseCorsAccessor();
 
+        // 限流组件(在跨域之后)
+        app.UseIpRateLimiting();
+        app.UseClientRateLimiting();
+
         app.UseAuthentication();
         app.UseAuthorization();
 

+ 0 - 28
Admin.NET/Admin.NET.Web.Entry/appsettings.json

@@ -26,32 +26,4 @@
     }
   },
   "AllowedHosts": "*"
-
-  //"Serilog": {
-  //  "MinimumLevel": {
-  //    "Default": "Information",
-  //    "Override": {
-  //      "System": "Warning",
-  //      "Microsoft": "Warning",
-  //      "Microsoft.Hosting.Lifetime": "Information",
-  //      "Microsoft.EntityFrameworkCore": "Information"
-  //    }
-  //  },
-  //  "WriteTo": [
-  //    {
-  //      "Name": "Console",
-  //      "Args": {
-  //        "outputTemplate": "【时间】{Timestamp:yyyy-MM-dd HH:mm:ss,fff}{NewLine}【等级】{Level:u3}{NewLine}【消息】{Message:lj}{NewLine}{NewLine}"
-  //      }
-  //    },
-  //    {
-  //      "Name": "File",
-  //      "Args": {
-  //        "path": "logs/.log",
-  //        "rollingInterval": "Day",
-  //        "outputTemplate": "【时间】{Timestamp:yyyy-MM-dd HH:mm:ss,fff}{NewLine}【等级】{Level:u3}{NewLine}【消息】{Message:lj}{NewLine}{NewLine}"
-  //      }
-  //    }
-  //  ]
-  //},
 }