fix bug 63687: added rate limiting for api
This commit is contained in:
parent
ceb2a85979
commit
720a2817f8
@ -26,6 +26,8 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.3" />
|
||||
<PackageReference Include="RedisRateLimiting" Version="1.0.11" />
|
||||
<PackageReference Include="RedisRateLimiting.AspNetCore" Version="1.0.8" />
|
||||
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="9.1.0" />
|
||||
<PackageReference Include="StackExchange.Redis.Extensions.Newtonsoft" Version="9.1.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using Role = ASC.Common.Security.Authorizing.Role;
|
||||
|
||||
namespace ASC.Api.Core.Auth;
|
||||
|
||||
[Scope]
|
||||
|
@ -100,6 +100,88 @@ public abstract class BaseStartup
|
||||
}
|
||||
});
|
||||
|
||||
var redisOptions = _configuration.GetSection("Redis").Get<RedisConfiguration>().ConfigurationOptions;
|
||||
var connectionMultiplexer = ConnectionMultiplexer.Connect(redisOptions);
|
||||
|
||||
services.AddRateLimiter(options =>
|
||||
{
|
||||
options.GlobalLimiter = PartitionedRateLimiter.CreateChained(
|
||||
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
||||
{
|
||||
var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value;
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
return RateLimitPartition.GetNoLimiter("no_limiter");
|
||||
}
|
||||
|
||||
var permitLimit = 1500;
|
||||
|
||||
string partitionKey;
|
||||
|
||||
partitionKey = $"fw_{userId}";
|
||||
|
||||
return RedisRateLimitPartition.GetFixedWindowRateLimiter(partitionKey, key => new RedisFixedWindowRateLimiterOptions
|
||||
{
|
||||
PermitLimit = permitLimit,
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
ConnectionMultiplexerFactory = () => connectionMultiplexer
|
||||
});
|
||||
}),
|
||||
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
||||
{
|
||||
var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value;
|
||||
string partitionKey;
|
||||
int permitLimit;
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
return RateLimitPartition.GetNoLimiter("no_limiter");
|
||||
}
|
||||
|
||||
if (String.Compare(httpContext.Request.Method, "GET", true) == 0)
|
||||
{
|
||||
permitLimit = 50;
|
||||
partitionKey = $"cr_read_{userId}";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
permitLimit = 15;
|
||||
partitionKey = $"cr_write_{userId}";
|
||||
}
|
||||
|
||||
return RedisRateLimitPartition.GetConcurrencyRateLimiter(partitionKey, key => new RedisConcurrencyRateLimiterOptions
|
||||
{
|
||||
PermitLimit = permitLimit,
|
||||
QueueLimit = 0,
|
||||
ConnectionMultiplexerFactory = () => connectionMultiplexer
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
options.AddPolicy("sensitive_api", httpContext => {
|
||||
var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value;
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
return RateLimitPartition.GetNoLimiter("no_limiter");
|
||||
}
|
||||
|
||||
var permitLimit = 5;
|
||||
var partitionKey = $"sensitive_api_{userId}";
|
||||
|
||||
return RedisRateLimitPartition.GetFixedWindowRateLimiter(partitionKey, key => new RedisFixedWindowRateLimiterOptions
|
||||
{
|
||||
PermitLimit = permitLimit,
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
ConnectionMultiplexerFactory = () => connectionMultiplexer
|
||||
});
|
||||
});
|
||||
|
||||
options.OnRejected = (context, ct) => RateLimitMetadata.OnRejected(context.HttpContext, context.Lease, ct);
|
||||
});
|
||||
|
||||
services.AddScoped<EFLoggerFactory>();
|
||||
|
||||
services.AddBaseDbContextPool<AccountLinkContext>()
|
||||
@ -311,6 +393,8 @@ public abstract class BaseStartup
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseRateLimiter();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseCultureMiddleware();
|
||||
@ -346,6 +430,8 @@ public abstract class BaseStartup
|
||||
await context.Response.WriteAsync($"{Environment.MachineName} running {CustomHealthCheck.Running}");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void ConfigureContainer(ContainerBuilder builder)
|
||||
|
@ -41,6 +41,7 @@ global using System.Text.Encodings.Web;
|
||||
global using System.Text.Json;
|
||||
global using System.Text.Json.Serialization;
|
||||
global using System.Text.RegularExpressions;
|
||||
global using System.Threading.RateLimiting;
|
||||
global using System.Web;
|
||||
global using System.Xml.Linq;
|
||||
|
||||
@ -150,6 +151,10 @@ global using NLog.Web;
|
||||
|
||||
global using RabbitMQ.Client;
|
||||
|
||||
global using RedisRateLimiting;
|
||||
global using RedisRateLimiting.AspNetCore;
|
||||
|
||||
global using StackExchange.Redis;
|
||||
global using StackExchange.Redis.Extensions.Core.Configuration;
|
||||
global using StackExchange.Redis.Extensions.Newtonsoft;
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
namespace ASC.People.Api;
|
||||
|
||||
public class UserController : PeopleControllerBase
|
||||
@ -1222,6 +1224,7 @@ public class UserController : PeopleControllerBase
|
||||
[AllowNotPayment]
|
||||
[AllowAnonymous]
|
||||
[HttpPost("password")]
|
||||
[EnableRateLimiting("sensitive_api")]
|
||||
public async Task<object> SendUserPasswordAsync(MemberRequestDto inDto)
|
||||
{
|
||||
if (_authContext.IsAuthenticated)
|
||||
|
Loading…
Reference in New Issue
Block a user