using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; using LingAdmin.ApiGateway.Middleware; var builder = WebApplication.CreateBuilder(args); // Add Dapr builder.Services.AddControllers().AddDapr(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new() { Title = "LingAdmin API Gateway", Version = "v1" }); c.AddSecurityDefinition("Bearer", new() { Description = "JWT Authorization header using the Bearer scheme", Name = "Authorization", In = Microsoft.OpenApi.Models.ParameterLocation.Header, Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey, Scheme = "Bearer" }); c.AddSecurityRequirement(new() { { new() { Reference = new() { Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme, Id = "Bearer" } }, Array.Empty() } }); }); // Configure JWT Authentication var jwtSettings = builder.Configuration.GetSection("JwtSettings"); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings["Issuer"], ValidAudience = jwtSettings["Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(jwtSettings["SecretKey"] ?? throw new InvalidOperationException("JWT SecretKey not configured"))) }; }); // Configure CORS builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); // Add YARP Reverse Proxy builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy")); // Add HttpClient for Dapr service invocation builder.Services.AddHttpClient(); // Add rate limiting builder.Services.AddRateLimiter(options => { options.GlobalLimiter = System.Threading.RateLimiting.PartitionedRateLimiter.Create(context => System.Threading.RateLimiting.RateLimitPartition.GetFixedWindowLimiter( partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "anonymous", factory: _ => new System.Threading.RateLimiting.FixedWindowRateLimiterOptions { PermitLimit = 100, Window = TimeSpan.FromMinutes(1) })); options.RejectionStatusCode = 429; }); var app = builder.Build(); // Configure pipeline if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseCors("AllowAll"); app.UseRateLimiter(); // Custom middleware for request logging app.UseMiddleware(); app.UseAuthentication(); app.UseAuthorization(); app.UseCloudEvents(); app.MapControllers(); app.MapSubscribeHandler(); // Map reverse proxy app.MapReverseProxy(); app.Run();