122 lines
4.2 KiB
C#
122 lines
4.2 KiB
C#
using Microsoft.IdentityModel.Tokens;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using ScrapperAPI.Bus;
|
|
using ScrapperAPI.Factories;
|
|
using ScrapperAPI.Hub;
|
|
using ScrapperAPI.Interfaces;
|
|
using ScrapperAPI.Options;
|
|
using ScrapperAPI.Repositories;
|
|
using ScrapperAPI.Services;
|
|
using ScrapperAPI.Utils;
|
|
using ScrapperAPI.Workers;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
builder.Services.AddOpenApi();
|
|
builder.Services.AddSignalR();
|
|
builder.Services.AddControllers();
|
|
|
|
// Authentik (OIDC) - JWT Bearer validation for API + SignalR
|
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
.AddJwtBearer(options =>
|
|
{
|
|
// Example: https://auth.seu-dominio.com/application/o/seu-app/
|
|
options.Authority = builder.Configuration["Authentication:Authority"];
|
|
options.RequireHttpsMetadata = builder.Configuration.GetValue("Authentication:RequireHttpsMetadata", true);
|
|
|
|
// Usually the SPA client_id
|
|
options.Audience = builder.Configuration["Authentication:Audience"];
|
|
|
|
// SignalR sends the token via the query string (access_token) for WebSockets
|
|
options.Events = new JwtBearerEvents
|
|
{
|
|
OnMessageReceived = context =>
|
|
{
|
|
var accessToken = context.Request.Query["access_token"];
|
|
var path = context.HttpContext.Request.Path;
|
|
|
|
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/ws/scrape"))
|
|
{
|
|
context.Token = accessToken;
|
|
}
|
|
|
|
return System.Threading.Tasks.Task.CompletedTask;
|
|
}
|
|
};
|
|
|
|
// If you want stricter token validation, uncomment:
|
|
// options.TokenValidationParameters = new TokenValidationParameters
|
|
// {
|
|
// ValidateIssuer = true,
|
|
// ValidateAudience = true,
|
|
// };
|
|
});
|
|
|
|
builder.Services.AddAuthorization(options =>
|
|
{
|
|
// Require authentication by default for ALL endpoints (controllers + hub)
|
|
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
|
.RequireAuthenticatedUser()
|
|
.Build();
|
|
});
|
|
|
|
builder.Services.Configure<ScraperOptions>(builder.Configuration.GetSection("Scraper"));
|
|
|
|
builder.Services.AddSingleton<IDomainRateLimiter>(sp =>
|
|
{
|
|
var opts = sp.GetRequiredService<Microsoft.Extensions.Options.IOptions<ScraperOptions>>().Value;
|
|
return new DomainRateLimiter(opts.RateLimit.PerDomainMinDelayMs);
|
|
});
|
|
builder.Services.AddSingleton<IScrapeEventBus, SignalRScrapeEventBus>();
|
|
builder.Services.AddSingleton<IScraperHttpClient, ScraperHttpClient>();
|
|
builder.Services.AddSingleton<IDbConnectionFactory, NpgsqlConnectionFactory>();
|
|
|
|
builder.Services.AddScoped<ISessionRepository, SessionRepository>();
|
|
builder.Services.AddScoped<IQueueRepository, QueueRepository>();
|
|
builder.Services.AddScoped<IContentRepository, ContentRepository>();
|
|
|
|
// Extraction
|
|
builder.Services.AddSingleton<ExtractionEngine>();
|
|
builder.Services.AddScoped<IExtractionModelRepository, ExtractionModelRepository>();
|
|
builder.Services.AddScoped<IExtractionRunRepository, ExtractionRunRepository>();
|
|
builder.Services.AddScoped<IExtractedDataRepository, ExtractedDataRepository>();
|
|
|
|
builder.Services.AddHttpClient("scraper", c => c.Timeout = TimeSpan.FromSeconds(30));
|
|
|
|
builder.Services.AddSingleton<IScrapeCoordinator, ScrapeCoordinator>();
|
|
builder.Services.AddHostedService(sp => (ScrapeCoordinator)sp.GetRequiredService<IScrapeCoordinator>());
|
|
|
|
builder.Services.AddSingleton<IExtractionCoordinator, ExtractionCoordinator>();
|
|
builder.Services.AddHostedService(sp => (ExtractionCoordinator)sp.GetRequiredService<IExtractionCoordinator>());
|
|
|
|
builder.Services.AddCors(options =>
|
|
{
|
|
options.AddPolicy("AllowReact",
|
|
policy =>
|
|
{
|
|
policy.WithOrigins("http://localhost:3000")
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod()
|
|
.AllowCredentials();
|
|
});
|
|
});
|
|
|
|
var app = builder.Build();
|
|
|
|
app.UseCors("AllowReact");
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.MapOpenApi().AllowAnonymous();
|
|
}
|
|
|
|
app.MapControllers();
|
|
app.MapHub<ScrapeHub>("/ws/scrape").RequireAuthorization();
|
|
|
|
// app.UseHttpsRedirection();
|
|
|
|
app.Run(); |