如何动态设置对OpenIdConnect中间件选项的授权? [英] How can I set the Authority on OpenIdConnect middleware options dynamically?
问题描述
我们有多个租户,他们使用不同的权限(他们自己的权限,而不仅仅是标准提供者).虽然我知道如何动态设置clientId和secret,但我不知道如何设置权限.设置一次,在启动过程中,之后将无法更改(或看起来是这样).
We have multiple tenants, and they use different authorities (their own, not just standard providers). While I know how to dynamically set the clientId and secret, I can't figure out how to set the authority. It is set once, during startup, and afterwards it cannot be changed (or so it seems).
由于我们有很多租户,所以我们不想在启动时全部注册,也不想在添加租户时要求重新启动.
Since we have a lot of tenants we don't want to register all at startup, and we also don't want to require a restart when tenants are added.
关于如何解决此问题的任何建议?我很想使用现有的中间件,但是如果不可能的话,我可以编写自己的中间件.
Any suggestions how I can go about this? I'd love to use the existing middleware, but if it's not possible I could write my own.
感谢任何建议!
推荐答案
虽然有些棘手,但绝对有可能.这是一个简化的示例,使用MSFT OIDC处理程序,自定义监视器和基于路径的租户解析:
While a bit tricky, it's definitely possible. Here's a simplified example, using the MSFT OIDC handler, a custom monitor and path-based tenant resolution:
public class TenantProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
public TenantProvider(IHttpContextAccessor httpContextAccessor)
=> _httpContextAccessor = httpContextAccessor;
public string GetCurrentTenant()
{
// This sample uses the path base as the tenant.
// You can replace that by your own logic.
string tenant = _httpContextAccessor.HttpContext.Request.PathBase;
if (string.IsNullOrEmpty(tenant))
{
tenant = "default";
}
return tenant;
}
}
public void Configure(IApplicationBuilder app)
{
app.Use(next => context =>
{
// This snippet uses a hardcoded resolution logic.
// In a real world app, you'd want to customize that.
if (context.Request.Path.StartsWithSegments("/fabrikam", out PathString path))
{
context.Request.PathBase = "/fabrikam";
context.Request.Path = path;
}
return next(context);
});
app.UseAuthentication();
app.UseMvc();
}
实施自定义IOptionsMonitor<OpenIdConnectOptions>
:
public class OpenIdConnectOptionsProvider : IOptionsMonitor<OpenIdConnectOptions>
{
private readonly ConcurrentDictionary<(string name, string tenant), Lazy<OpenIdConnectOptions>> _cache;
private readonly IOptionsFactory<OpenIdConnectOptions> _optionsFactory;
private readonly TenantProvider _tenantProvider;
public OpenIdConnectOptionsProvider(
IOptionsFactory<OpenIdConnectOptions> optionsFactory,
TenantProvider tenantProvider)
{
_cache = new ConcurrentDictionary<(string, string), Lazy<OpenIdConnectOptions>>();
_optionsFactory = optionsFactory;
_tenantProvider = tenantProvider;
}
public OpenIdConnectOptions CurrentValue => Get(Options.DefaultName);
public OpenIdConnectOptions Get(string name)
{
var tenant = _tenantProvider.GetCurrentTenant();
Lazy<OpenIdConnectOptions> Create() => new Lazy<OpenIdConnectOptions>(() => _optionsFactory.Create(name));
return _cache.GetOrAdd((name, tenant), _ => Create()).Value;
}
public IDisposable OnChange(Action<OpenIdConnectOptions, string> listener) => null;
}
实施自定义IConfigureNamedOptions<OpenIdConnectOptions>
:
public class OpenIdConnectOptionsInitializer : IConfigureNamedOptions<OpenIdConnectOptions>
{
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly TenantProvider _tenantProvider;
public OpenIdConnectOptionsInitializer(
IDataProtectionProvider dataProtectionProvider,
TenantProvider tenantProvider)
{
_dataProtectionProvider = dataProtectionProvider;
_tenantProvider = tenantProvider;
}
public void Configure(string name, OpenIdConnectOptions options)
{
if (!string.Equals(name, OpenIdConnectDefaults.AuthenticationScheme, StringComparison.Ordinal))
{
return;
}
var tenant = _tenantProvider.GetCurrentTenant();
// Create a tenant-specific data protection provider to ensure
// encrypted states can't be read/decrypted by the other tenants.
options.DataProtectionProvider = _dataProtectionProvider.CreateProtector(tenant);
// Other tenant-specific options like options.Authority can be registered here.
}
public void Configure(OpenIdConnectOptions options)
=> Debug.Fail("This infrastructure method shouldn't be called.");
}
在您的DI容器中注册服务:
public void ConfigureServices(IServiceCollection services)
{
// ...
// Register the OpenID Connect handler.
services.AddAuthentication()
.AddOpenIdConnect();
services.AddSingleton<TenantProvider>();
services.AddSingleton<IOptionsMonitor<OpenIdConnectOptions>, OpenIdConnectOptionsProvider>();
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectOptionsInitializer>();
}
这篇关于如何动态设置对OpenIdConnect中间件选项的授权?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!