feat: 新增速率限制滑动限流
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
using Volo.Abp.Uow;
|
using Volo.Abp.Uow;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
||||||
@@ -117,5 +118,19 @@ namespace Yi.Abp.Application.Services
|
|||||||
var entity = new BannerEntity();
|
var entity = new BannerEntity();
|
||||||
var dto = entity.Adapt<BannerGetListOutputDto>();
|
var dto = entity.Adapt<BannerGetListOutputDto>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 速率限制
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
// [DisableRateLimiting]
|
||||||
|
//[EnableRateLimiting("sliding")]
|
||||||
|
public int GetRateLimiting()
|
||||||
|
{
|
||||||
|
RequestNumber++;
|
||||||
|
return RequestNumber;
|
||||||
|
}
|
||||||
|
private static int RequestNumber { get; set; } = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System.Text;
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.RateLimiting;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
@@ -84,12 +87,12 @@ namespace Yi.Abp.Web
|
|||||||
});
|
});
|
||||||
|
|
||||||
//设置缓存不要过期,默认滑动20分钟
|
//设置缓存不要过期,默认滑动20分钟
|
||||||
Configure<AbpDistributedCacheOptions>(cacheOptions =>
|
Configure<AbpDistributedCacheOptions>(cacheOptions =>
|
||||||
{
|
{
|
||||||
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration =null;
|
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
|
||||||
//缓存key前缀
|
//缓存key前缀
|
||||||
cacheOptions.KeyPrefix = "Yi:";
|
cacheOptions.KeyPrefix = "Yi:";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Configure<AbpAntiForgeryOptions>(options =>
|
Configure<AbpAntiForgeryOptions>(options =>
|
||||||
@@ -135,24 +138,62 @@ namespace Yi.Abp.Web
|
|||||||
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
|
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//速率限制
|
||||||
|
//每60秒限制100个请求,滑块添加,分6段
|
||||||
|
service.AddRateLimiter(_ =>
|
||||||
|
{
|
||||||
|
_.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
||||||
|
_.OnRejected = (context, _) =>
|
||||||
|
{
|
||||||
|
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
|
||||||
|
{
|
||||||
|
context.HttpContext.Response.Headers.RetryAfter =
|
||||||
|
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
|
||||||
|
}
|
||||||
|
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
|
||||||
|
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
|
||||||
|
|
||||||
|
return new ValueTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
//全局使用,链式表达式
|
||||||
|
_.GlobalLimiter = PartitionedRateLimiter.CreateChained(
|
||||||
|
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
||||||
|
{
|
||||||
|
var userAgent = httpContext.Request.Headers.UserAgent.ToString();
|
||||||
|
|
||||||
|
return RateLimitPartition.GetSlidingWindowLimiter
|
||||||
|
(userAgent, _ =>
|
||||||
|
new SlidingWindowRateLimiterOptions
|
||||||
|
{
|
||||||
|
PermitLimit = 100,
|
||||||
|
Window = TimeSpan.FromSeconds(60),
|
||||||
|
SegmentsPerWindow = 6,
|
||||||
|
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//jwt鉴权
|
//jwt鉴权
|
||||||
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
|
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
|
||||||
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
|
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
|
||||||
|
|
||||||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
.AddJwtBearer(options =>
|
.AddJwtBearer(options =>
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
{
|
||||||
ClockSkew = TimeSpan.Zero,
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
ValidateIssuerSigningKey = true,
|
{
|
||||||
ValidIssuer = jwtOptions.Issuer,
|
ClockSkew = TimeSpan.Zero,
|
||||||
ValidAudience = jwtOptions.Audience,
|
ValidateIssuerSigningKey = true,
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
ValidIssuer = jwtOptions.Issuer,
|
||||||
};
|
ValidAudience = jwtOptions.Audience,
|
||||||
options.Events = new JwtBearerEvents
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
||||||
{
|
};
|
||||||
OnMessageReceived = context =>
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = context =>
|
||||||
{
|
{
|
||||||
var accessToken = context.Request.Query["access_token"];
|
var accessToken = context.Request.Query["access_token"];
|
||||||
if (!string.IsNullOrEmpty(accessToken))
|
if (!string.IsNullOrEmpty(accessToken))
|
||||||
@@ -161,21 +202,21 @@ namespace Yi.Abp.Web
|
|||||||
}
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.AddJwtBearer(TokenTypeConst.Refresh, options =>
|
.AddJwtBearer(TokenTypeConst.Refresh, options =>
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
{
|
||||||
ClockSkew = TimeSpan.Zero,
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
ValidateIssuerSigningKey = true,
|
{
|
||||||
ValidIssuer = refreshJwtOptions.Issuer,
|
ClockSkew = TimeSpan.Zero,
|
||||||
ValidAudience = refreshJwtOptions.Audience,
|
ValidateIssuerSigningKey = true,
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
|
ValidIssuer = refreshJwtOptions.Issuer,
|
||||||
};
|
ValidAudience = refreshJwtOptions.Audience,
|
||||||
options.Events = new JwtBearerEvents
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
|
||||||
{
|
};
|
||||||
OnMessageReceived = context =>
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = context =>
|
||||||
{
|
{
|
||||||
var refresh_token = context.Request.Headers["refresh_token"];
|
var refresh_token = context.Request.Headers["refresh_token"];
|
||||||
if (!string.IsNullOrEmpty(refresh_token))
|
if (!string.IsNullOrEmpty(refresh_token))
|
||||||
@@ -191,17 +232,17 @@ namespace Yi.Abp.Web
|
|||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})
|
})
|
||||||
.AddQQ(options =>
|
.AddQQ(options =>
|
||||||
{
|
{
|
||||||
configuration.GetSection("OAuth:QQ").Bind(options);
|
configuration.GetSection("OAuth:QQ").Bind(options);
|
||||||
})
|
})
|
||||||
.AddGitee(options =>
|
.AddGitee(options =>
|
||||||
{
|
{
|
||||||
configuration.GetSection("OAuth:Gitee").Bind(options);
|
configuration.GetSection("OAuth:Gitee").Bind(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
//授权
|
//授权
|
||||||
context.Services.AddAuthorization();
|
context.Services.AddAuthorization();
|
||||||
@@ -221,6 +262,9 @@ namespace Yi.Abp.Web
|
|||||||
//跨域
|
//跨域
|
||||||
app.UseCors(DefaultCorsPolicyName);
|
app.UseCors(DefaultCorsPolicyName);
|
||||||
|
|
||||||
|
//速率限制
|
||||||
|
app.UseRateLimiter();
|
||||||
|
|
||||||
//无感token,先刷新再鉴权
|
//无感token,先刷新再鉴权
|
||||||
app.UseRefreshToken();
|
app.UseRefreshToken();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user