- ASP.NET Core 내장 Rate Limiting (FixedWindow, IP 기반 분당 100회) - 한도 초과 시 HTTP 429 + ApiResponse(에러코드 106) 반환 - Swashbuckle.AspNetCore 6.9.0 기반 Swagger UI 추가 - 도메인별 API 문서 그룹 (all, public, auth 등 10개) - JWT Bearer 인증 UI (Authorize 버튼) - X-Service-Code/X-API-KEY 커스텀 헤더 자동 표시 필터 - Microsoft.AspNetCore.OpenApi 제거 (Swashbuckle과 호환 충돌) Closes #30
55 lines
1.8 KiB
C#
55 lines
1.8 KiB
C#
using System.Threading.RateLimiting;
|
|
using Serilog;
|
|
using SPMS.API.Extensions;
|
|
using SPMS.Application;
|
|
using SPMS.Domain.Common;
|
|
using SPMS.Infrastructure;
|
|
|
|
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
|
{
|
|
WebRootPath = Environment.GetEnvironmentVariable("ASPNETCORE_WEBROOT")
|
|
?? "wwwroot"
|
|
});
|
|
|
|
// ===== 1. Serilog =====
|
|
builder.Host.UseSerilog((context, config) =>
|
|
config.ReadFrom.Configuration(context.Configuration));
|
|
|
|
// ===== 2. Services (DI) =====
|
|
builder.Services.AddApplication();
|
|
builder.Services.AddInfrastructure(builder.Configuration);
|
|
|
|
// ===== 3. Presentation =====
|
|
builder.Services.AddControllers();
|
|
builder.Services.AddSwaggerDocumentation();
|
|
builder.Services.AddJwtAuthentication(builder.Configuration);
|
|
builder.Services.AddAuthorizationPolicies();
|
|
|
|
// ===== 4. Rate Limiting =====
|
|
builder.Services.AddRateLimiter(options =>
|
|
{
|
|
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
|
options.OnRejected = async (context, cancellationToken) =>
|
|
{
|
|
context.HttpContext.Response.ContentType = "application/json";
|
|
var response = ApiResponse.Fail(
|
|
ErrorCodes.LimitExceeded, "요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요.");
|
|
await context.HttpContext.Response.WriteAsJsonAsync(response, cancellationToken);
|
|
};
|
|
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
|
RateLimitPartition.GetFixedWindowLimiter(
|
|
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
|
|
factory: _ => new FixedWindowRateLimiterOptions
|
|
{
|
|
PermitLimit = 100,
|
|
Window = TimeSpan.FromMinutes(1)
|
|
}));
|
|
});
|
|
|
|
var app = builder.Build();
|
|
|
|
// ===== 5. Middleware Pipeline =====
|
|
app.UseMiddlewarePipeline();
|
|
|
|
app.Run();
|