fix(backend): add TenantDbTransactionInterceptor for RLS with explicit transactions

Implements Option D: wraps auto-commit reads in explicit transactions with SET LOCAL.
Handles transaction lifecycle (create→SET LOCAL→execute→commit/dispose).
Uses IDbTransactionInterceptor for EF-managed SaveChanges transactions.
Critical fix for PostgreSQL RLS requiring transaction-scoped context.
This commit is contained in:
WorkClub Automation
2026-03-05 20:43:03 +01:00
parent 5fb148a9eb
commit c918f447b2
2 changed files with 307 additions and 2 deletions

View File

@@ -27,7 +27,7 @@ builder.Services.AddScoped<ClubService>();
builder.Services.AddScoped<MemberService>();
builder.Services.AddScoped<MemberSyncService>();
builder.Services.AddScoped<TenantDbConnectionInterceptor>();
builder.Services.AddScoped<TenantDbTransactionInterceptor>();
builder.Services.AddSingleton<SaveChangesTenantInterceptor>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
@@ -36,6 +36,7 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
options.Authority = builder.Configuration["Keycloak:Authority"];
options.Audience = builder.Configuration["Keycloak:Audience"];
options.RequireHttpsMetadata = false;
options.MapInboundClaims = false;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false, // Disabled for local dev - external clients use localhost:8080, internal use keycloak:8080
@@ -56,7 +57,7 @@ builder.Services.AddAuthorizationBuilder()
builder.Services.AddDbContext<AppDbContext>((sp, options) =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))
.AddInterceptors(
sp.GetRequiredService<TenantDbConnectionInterceptor>(),
sp.GetRequiredService<TenantDbTransactionInterceptor>(),
sp.GetRequiredService<SaveChangesTenantInterceptor>()));
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");