141 lines
3.9 KiB
C#
141 lines
3.9 KiB
C#
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
|
using AMREZ.EOP.API.Middleware;
|
|
using AMREZ.EOP.Domain.Shared.Contracts;
|
|
using AMREZ.EOP.Domain.Shared.Tenancy;
|
|
using AMREZ.EOP.Infrastructures.Data;
|
|
using AMREZ.EOP.Infrastructures.DependencyInjections;
|
|
using AMREZ.EOP.Infrastructures.Options;
|
|
using AMREZ.EOP.Infrastructures.Tenancy;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Options;
|
|
using Microsoft.OpenApi.Models;
|
|
using Npgsql;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
builder.Services.Configure<AuthOptions>(builder.Configuration.GetSection("Connections"));
|
|
|
|
builder.Services.AddInfrastructure();
|
|
|
|
builder.Services.AddOpenApi();
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen(c =>
|
|
{
|
|
c.SwaggerDoc("v1", new OpenApiInfo
|
|
{
|
|
Title = "AMREZ.EOP API",
|
|
Version = "v1"
|
|
});
|
|
|
|
// Cookie auth (ชื่อคุกกี้ eop.auth)
|
|
c.AddSecurityDefinition("cookieAuth", new OpenApiSecurityScheme
|
|
{
|
|
Type = SecuritySchemeType.ApiKey,
|
|
In = ParameterLocation.Cookie,
|
|
Name = "eop.auth",
|
|
Description = "Sign in via /api/authentication/login to receive cookie."
|
|
});
|
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme{
|
|
Reference = new OpenApiReference{ Type = ReferenceType.SecurityScheme, Id = "cookieAuth" }
|
|
},
|
|
Array.Empty<string>()
|
|
}
|
|
});
|
|
});
|
|
|
|
builder.Services
|
|
.AddAuthentication(AuthPolicies.Scheme)
|
|
.AddCookie(AuthPolicies.Scheme, o => { o.LoginPath="/api/authentication/login"; o.Cookie.Name="eop.auth"; o.SlidingExpiration=true; });
|
|
|
|
builder.Services.AddAuthorization();
|
|
|
|
builder.Services.AddSingleton(new StrictTenantGuardOptions
|
|
{
|
|
PlatformSlug = "public",
|
|
HeaderName = "X-Tenant",
|
|
ClaimName = "tenant"
|
|
});
|
|
builder.Services.AddTransient<StrictTenantGuardMiddleware>();
|
|
|
|
builder.Services.AddControllers();
|
|
|
|
var app = builder.Build();
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
await ApplyMigrationsAsync(app.Services);
|
|
|
|
app.MapOpenApi();
|
|
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI(o =>
|
|
{
|
|
o.SwaggerEndpoint("/swagger/v1/swagger.json", "AMREZ.EOP API v1");
|
|
o.RoutePrefix = "swagger";
|
|
o.DisplayRequestDuration();
|
|
});
|
|
}
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
app.UseAuthentication();
|
|
|
|
app.UseMiddleware<StrictTenantGuardMiddleware>();
|
|
|
|
app.UseAuthorization();
|
|
|
|
app.MapControllers();
|
|
|
|
app.Run();
|
|
|
|
static async Task ApplyMigrationsAsync(IServiceProvider services)
|
|
{
|
|
using var scope = services.CreateScope();
|
|
var sp = scope.ServiceProvider;
|
|
|
|
var opts = sp.GetRequiredService<Microsoft.Extensions.Options.IOptions<AuthOptions>>().Value;
|
|
var factory = sp.GetRequiredService<ITenantDbContextFactory>();
|
|
|
|
if (!opts.UseSchemaPerTenant)
|
|
{
|
|
await using var db = factory.Create<AppDbContext>(new TenantContext { Id = "_shared_" });
|
|
await db.Database.MigrateAsync();
|
|
}
|
|
|
|
var schemas = await GetAppSchemasAsync(opts.DefaultConnection);
|
|
|
|
foreach (var schema in schemas)
|
|
{
|
|
var t = new TenantContext { Id = schema, Schema = schema, Mode = TenantMode.Schema };
|
|
await using var db = factory.Create<AppDbContext>(t);
|
|
await db.Database.MigrateAsync();
|
|
}
|
|
}
|
|
|
|
static async Task<List<string>> GetAppSchemasAsync(string connectionString)
|
|
{
|
|
var list = new List<string>();
|
|
|
|
await using var conn = new NpgsqlConnection(connectionString);
|
|
await conn.OpenAsync();
|
|
|
|
const string sql = @"
|
|
SELECT nspname
|
|
FROM pg_namespace
|
|
WHERE nspname NOT LIKE 'pg_%'
|
|
AND nspname <> 'information_schema'
|
|
ORDER BY nspname;";
|
|
|
|
await using var cmd = new NpgsqlCommand(sql, conn);
|
|
await using var rd = await cmd.ExecuteReaderAsync();
|
|
while (await rd.ReadAsync())
|
|
list.Add(rd.GetString(0));
|
|
|
|
if (list.Count == 0) list.Add("public");
|
|
|
|
return list;
|
|
} |