From d83bb3b8341d6de6ac68e4277d7ee8eda79a2a6f Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sun, 9 Feb 2025 08:24:55 +0100 Subject: [PATCH] Add customizable tenant header support for HTTP routing Introduced `MultitenancyHttpOptions` to configure the tenant header name used for HTTP routing. Updated `HeaderTenantResolver` to utilize this option and modified the server setup to allow overriding the default header name. This enables more flexible multitenancy configurations. --- src/apps/Elsa.Server.Web/Program.cs | 6 ++++- .../Features/MultitenantHttpRoutingFeature.cs | 24 +++++++++++++++++++ .../Options/MultitenancyHttpOptions.cs | 6 +++++ .../Resolvers/HeaderTenantResolver.cs | 7 ++++-- 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/modules/Elsa.Tenants.AspNetCore/Options/MultitenancyHttpOptions.cs diff --git a/src/apps/Elsa.Server.Web/Program.cs b/src/apps/Elsa.Server.Web/Program.cs index e22f276fd..32fdbfc5c 100644 --- a/src/apps/Elsa.Server.Web/Program.cs +++ b/src/apps/Elsa.Server.Web/Program.cs @@ -659,7 +659,11 @@ services } }); - elsa.UseTenantHttpRouting(); + elsa.UseTenantHttpRouting(tenantHttpRouting => + { + // Override the tenant header name with a custom one. + tenantHttpRouting.WithTenantHeader("X-Company-Id"); + }); } elsa.InstallDropIns(options => options.DropInRootDirectory = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "DropIns")); diff --git a/src/modules/Elsa.Tenants.AspNetCore/Features/MultitenantHttpRoutingFeature.cs b/src/modules/Elsa.Tenants.AspNetCore/Features/MultitenantHttpRoutingFeature.cs index 2def1e4d6..bdf0df3b8 100644 --- a/src/modules/Elsa.Tenants.AspNetCore/Features/MultitenantHttpRoutingFeature.cs +++ b/src/modules/Elsa.Tenants.AspNetCore/Features/MultitenantHttpRoutingFeature.cs @@ -3,6 +3,7 @@ using Elsa.Features.Abstractions; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Http.Features; +using Elsa.Tenants.AspNetCore.Options; using Elsa.Tenants.AspNetCore.Services; using Elsa.Tenants.Features; using Microsoft.Extensions.DependencyInjection; @@ -13,6 +14,26 @@ namespace Elsa.Tenants.AspNetCore.Features; [DependencyOf(typeof(TenantsFeature))] public class MultitenantHttpRoutingFeature(IModule module) : FeatureBase(module) { + private Action _configureMultitenancyHttpOptions = _ => { }; + + /// + /// Configures the MultitenantHttpRoutingFeature to use a specific tenant header name. + /// + /// The name of the HTTP header used to identify the tenant. + /// The current instance of for fluent configuration. + public MultitenantHttpRoutingFeature WithTenantHeader(string headerName) => WithMultitenancyHttpOptions(options => options.TenantHeaderName = headerName); + + /// + /// Configures the MultitenantHttpRoutingFeature with custom multitenancy HTTP options. + /// + /// The action to configure . + /// The current instance of for fluent configuration. + public MultitenantHttpRoutingFeature WithMultitenancyHttpOptions(Action configure) + { + _configureMultitenancyHttpOptions = configure; + return this; + } + public override void Configure() { Module.Configure(feature => @@ -24,6 +45,9 @@ public class MultitenantHttpRoutingFeature(IModule module) : FeatureBase(module) public override void Apply() { + // Multitenancy HTTP options. + Services.Configure(_configureMultitenancyHttpOptions); + // Tenant resolvers. Services .AddScoped() diff --git a/src/modules/Elsa.Tenants.AspNetCore/Options/MultitenancyHttpOptions.cs b/src/modules/Elsa.Tenants.AspNetCore/Options/MultitenancyHttpOptions.cs new file mode 100644 index 000000000..877400eb6 --- /dev/null +++ b/src/modules/Elsa.Tenants.AspNetCore/Options/MultitenancyHttpOptions.cs @@ -0,0 +1,6 @@ +namespace Elsa.Tenants.AspNetCore.Options; + +public class MultitenancyHttpOptions +{ + public string TenantHeaderName { get; set; } = "X-Tenant-Id"; +} \ No newline at end of file diff --git a/src/modules/Elsa.Tenants.AspNetCore/Resolvers/HeaderTenantResolver.cs b/src/modules/Elsa.Tenants.AspNetCore/Resolvers/HeaderTenantResolver.cs index 06d36e387..697049285 100644 --- a/src/modules/Elsa.Tenants.AspNetCore/Resolvers/HeaderTenantResolver.cs +++ b/src/modules/Elsa.Tenants.AspNetCore/Resolvers/HeaderTenantResolver.cs @@ -1,12 +1,14 @@ using Elsa.Common.Multitenancy; +using Elsa.Tenants.AspNetCore.Options; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; namespace Elsa.Tenants.AspNetCore; /// /// Resolves the tenant based on the header in the request. /// -public class HeaderTenantResolver(IHttpContextAccessor httpContextAccessor) : TenantResolverBase +public class HeaderTenantResolver(IHttpContextAccessor httpContextAccessor, IOptions options) : TenantResolverBase { protected override TenantResolverResult Resolve(TenantResolverContext context) { @@ -15,7 +17,8 @@ public class HeaderTenantResolver(IHttpContextAccessor httpContextAccessor) : Te if (httpContext == null) return Unresolved(); - var tenantId = httpContext.Request.Headers["X-Tenant-Id"].FirstOrDefault(); + var headerName = options.Value.TenantHeaderName; + var tenantId = httpContext.Request.Headers[headerName].FirstOrDefault(); return AutoResolve(tenantId); }