代码之家  ›  专栏  ›  技术社区  ›  Iris Classon

如何动态设置OpenIdConnect中间件选项的权限?

  •  2
  • Iris Classon  · 技术社区  · 7 年前

    我们有多个租户,他们使用不同的权限(他们自己的,而不仅仅是标准提供商)。虽然我知道如何动态设置clientId和secret,但我不知道如何设置权限。它在启动期间设置一次,之后就不能更改(或者看起来是这样)。

    谢谢你的建议!

    2 回复  |  直到 7 年前
        1
  •  14
  •   Kévin Chalet    7 年前

    虽然有点棘手,但绝对有可能。下面是一个简化的示例,使用MSFT OIDC处理程序、自定义监视器和基于路径的租户解析:

    实现租户解析逻辑。例如:

    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>();
    }
    
        2
  •  1
  •   Anders Abel    7 年前

    Asp.NET核心模型假定每个处理程序实例有一个上游权限。我的Saml2组件在一个处理程序中支持多个上游idp,当这种假设不再成立时,它在系统的其余部分中也有缺点。

    推荐文章