Добавил RateLimiter
All checks were successful
Create and publish a Docker image / Publish image (push) Successful in 11m22s
All checks were successful
Create and publish a Docker image / Publish image (push) Successful in 11m22s
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using SfeduSchedule.Services;
|
||||
|
||||
namespace SfeduSchedule.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[EnableRateLimiting("throttle")]
|
||||
public class ScheduleController(ModeusService modeusService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,6 +15,7 @@ namespace SfeduSchedule.Controllers
|
||||
/// <param name="attendeePersonId">Список GUID пользователей, для которых запрашивается расписание.</param>
|
||||
/// <returns>Список событий расписания.</returns>
|
||||
/// <response code="200">Возвращает расписание</response>
|
||||
/// <response code="429">Слишком много запросов</response>
|
||||
[HttpGet]
|
||||
[Route("test")]
|
||||
public async Task<IActionResult> Get([FromQuery] List<Guid> attendeePersonId, [FromQuery] DateTime? startDate, [FromQuery] DateTime? endDate)
|
||||
@@ -31,6 +34,7 @@ namespace SfeduSchedule.Controllers
|
||||
/// <param name="request">Объект запроса, содержащий параметры фильтрации расписания.</param>
|
||||
/// <returns>Список событий расписания.</returns>
|
||||
/// <response code="200">Возвращает расписание</response>
|
||||
/// <response code="429">Слишком много запросов</response>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Post([FromBody] ModeusScheduleRequest request)
|
||||
{
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using System.Threading.RateLimiting;
|
||||
using Microsoft.Identity.Web;
|
||||
using Quartz;
|
||||
using SfeduSchedule;
|
||||
@@ -13,13 +14,13 @@ string? tgChatId = configuration["TG_CHAT_ID"];
|
||||
string? tgToken = configuration["TG_TOKEN"];
|
||||
string updateJwtCron = configuration["UPDATE_JWT_CRON"] ?? "0 4 * ? * *";
|
||||
|
||||
|
||||
// создать папку data если не существует
|
||||
var dataDirectory = Path.Combine(AppContext.BaseDirectory, "data");
|
||||
if (!Directory.Exists(dataDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(dataDirectory);
|
||||
}
|
||||
|
||||
GlobalVariables.JwtFilePath = Path.Combine(dataDirectory, "jwt.txt");
|
||||
|
||||
|
||||
@@ -35,7 +36,8 @@ if (!string.IsNullOrEmpty(tgChatId) && !string.IsNullOrEmpty(tgToken))
|
||||
options.LogLevel = new Dictionary<string, LogLevel>
|
||||
{
|
||||
{ "Default", LogLevel.Error },
|
||||
{ "SfeduSchedule.Jobs.UpdateJwtJob", LogLevel.Information }
|
||||
{ "SfeduSchedule.Jobs.UpdateJwtJob", LogLevel.Information },
|
||||
{ "Program", LogLevel.Information }
|
||||
};
|
||||
});
|
||||
|
||||
@@ -70,12 +72,37 @@ builder.Services.AddSwaggerGen(options =>
|
||||
options.IncludeXmlComments(xmlPath);
|
||||
});
|
||||
|
||||
builder.Services.AddRateLimiter(options =>
|
||||
{
|
||||
options.AddPolicy("throttle", httpContext =>
|
||||
RateLimitPartition.GetFixedWindowLimiter(
|
||||
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
|
||||
factory: _ => new FixedWindowRateLimiterOptions
|
||||
{
|
||||
PermitLimit = 20,
|
||||
Window = TimeSpan.FromSeconds(10)
|
||||
}));
|
||||
|
||||
options.OnRejected = async (context, cancellationToken) =>
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
|
||||
context.HttpContext.Response.Headers["Retry-After"] = "60";
|
||||
|
||||
await context.HttpContext.Response.WriteAsync("Rate limit exceeded. Please try again later.",
|
||||
cancellationToken);
|
||||
|
||||
var reqLogger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
|
||||
reqLogger.LogWarning("Rate limit exceeded for IP: {IpAddress}",
|
||||
context.HttpContext.Connection.RemoteIpAddress);
|
||||
};
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
if (string.IsNullOrEmpty(preinstalledJwtToken))
|
||||
{
|
||||
var schedulerFactory = app.Services.GetRequiredService<ISchedulerFactory>();
|
||||
@@ -103,7 +130,8 @@ if (string.IsNullOrEmpty(preinstalledJwtToken))
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Файл jwt.txt не содержит дату истечения или она некорректна, выполняем обновление токена");
|
||||
logger.LogInformation(
|
||||
"Файл jwt.txt не содержит дату истечения или она некорректна, выполняем обновление токена");
|
||||
await scheduler.TriggerJob(jobKey);
|
||||
}
|
||||
}
|
||||
@@ -131,5 +159,6 @@ app.MapGet("/", async context =>
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
app.UseRateLimiter();
|
||||
|
||||
app.Run();
|
Reference in New Issue
Block a user