feat(api): configure API application startup
This commit is contained in:
108
src/IncidentOps.Api/Program.cs
Normal file
108
src/IncidentOps.Api/Program.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System.Text;
|
||||||
|
using FluentMigrator.Runner;
|
||||||
|
using Hangfire;
|
||||||
|
using Hangfire.Redis.StackExchange;
|
||||||
|
using IncidentOps.Api.Auth;
|
||||||
|
using IncidentOps.Infrastructure;
|
||||||
|
using IncidentOps.Infrastructure.Auth;
|
||||||
|
using IncidentOps.Infrastructure.Migrations;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add controllers
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
|
// Configure JWT settings
|
||||||
|
var jwtSettings = new JwtSettings
|
||||||
|
{
|
||||||
|
Issuer = builder.Configuration["Jwt:Issuer"] ?? "incidentops",
|
||||||
|
Audience = builder.Configuration["Jwt:Audience"] ?? "incidentops",
|
||||||
|
SigningKey = builder.Configuration["Jwt:SigningKey"] ?? throw new InvalidOperationException("JWT signing key not configured"),
|
||||||
|
AccessTokenExpirationMinutes = builder.Configuration.GetValue<int>("Jwt:AccessTokenExpirationMinutes", 15),
|
||||||
|
RefreshTokenExpirationDays = builder.Configuration.GetValue<int>("Jwt:RefreshTokenExpirationDays", 7)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure Infrastructure
|
||||||
|
var connectionString = builder.Configuration.GetConnectionString("Postgres")
|
||||||
|
?? throw new InvalidOperationException("Postgres connection string not configured");
|
||||||
|
builder.Services.AddInfrastructure(connectionString, jwtSettings);
|
||||||
|
|
||||||
|
// Configure FluentMigrator
|
||||||
|
builder.Services.AddFluentMigratorCore()
|
||||||
|
.ConfigureRunner(rb => rb
|
||||||
|
.AddPostgres()
|
||||||
|
.WithGlobalConnectionString(connectionString)
|
||||||
|
.ScanIn(typeof(Migration0001_InitialSchema).Assembly).For.Migrations())
|
||||||
|
.AddLogging(lb => lb.AddFluentMigratorConsole());
|
||||||
|
|
||||||
|
// Configure JWT Authentication
|
||||||
|
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.SigningKey))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure Authorization
|
||||||
|
builder.Services.AddSingleton<IAuthorizationHandler, RoleRequirementHandler>();
|
||||||
|
builder.Services.AddAuthorizationBuilder()
|
||||||
|
.AddPolicy("Viewer", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Viewer)))
|
||||||
|
.AddPolicy("Member", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Member)))
|
||||||
|
.AddPolicy("Admin", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Admin)));
|
||||||
|
|
||||||
|
// Configure Hangfire (client only - server runs in Worker)
|
||||||
|
var redisConnectionString = builder.Configuration["Redis:ConnectionString"]
|
||||||
|
?? throw new InvalidOperationException("Redis connection string not configured");
|
||||||
|
builder.Services.AddHangfire(configuration => configuration
|
||||||
|
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
||||||
|
.UseSimpleAssemblyNameTypeSerializer()
|
||||||
|
.UseRecommendedSerializerSettings()
|
||||||
|
.UseRedisStorage(ConnectionMultiplexer.Connect(redisConnectionString)));
|
||||||
|
|
||||||
|
// Add CORS
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddDefaultPolicy(policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins(builder.Configuration.GetSection("Cors:Origins").Get<string[]>() ?? ["http://localhost:3000"])
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Run migrations
|
||||||
|
using (var scope = app.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
|
||||||
|
runner.MigrateUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.MapOpenApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseCors();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
Reference in New Issue
Block a user