Как я могу добавить пользовательские таблицы в конфигурацию DBContext? - PullRequest
0 голосов
/ 07 февраля 2019

Я хочу настроить IdentityServer4 для загрузки внешних поставщиков удостоверений из базы данных.Я хотел бы расширить ConfigurationDBContext, чтобы включить DbSet Saml2Provider.В моем стартапе я бы хотел автоматически добавить Saml2Provider.В идеале я хотел бы, чтобы на странице входа в idsvr4 был простой способ обновления списка доступных провайдеров без перезапуска приложения.

Я смог загрузить Saml2Providers из БД и зарегистрировать их каквнешние провайдеры.Однако это использует ApplicationDbcontext, и он не обновляется при каждом запросе к idsvr.

Это мой работающий configureServices (использующий ApplicationDbContext для извлечения поставщиков из БД):

public void ConfigureServices(IServiceCollection services)

    services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(connectionString));
    var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
        })
            // this adds the config data from DB (clients, resources)
            .AddConfigurationStore(options =>
            {

                options.Client.Schema = "config";
                options.DefaultSchema = "config";
                options.ConfigureDbContext = b =>
                    b.UseSqlServer(connectionString,
                        sql =>        sql.MigrationsAssembly(migrationsAssembly));
            })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => 
                    b.UseSqlServer(connectionString,
                        sql => sql.MigrationsAssembly(migrationsAssembly));

                // this enables automatic token cleanup. this is optional.
                options.EnableTokenCleanup = true;
            })
            .AddAspNetIdentity<ApplicationUser>()
            .AddProfileService<CustomProfileService>();
......
    var context = serviceProvider.GetService<ApplicationDbContext>();

    var saml2Providers = context.Saml2Providers.ToList();
     foreach(var provider in saml2Providers)
     {
        provider.RegisterService(services);
     }
}

Это моя попытка расширить ConfigurationDbContext:

public class IdSrvConfigurationDbContext : ConfigurationDbContext<IdSrvConfigurationDbContext>
{
    public DbSet<Saml2Provider> Saml2Providers { get; set; }

    public IdSrvConfigurationDbContext(DbContextOptions<IdSrvConfigurationDbContext> options, ConfigurationStoreOptions storeOptions) 
        :base(options, storeOptions)            
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //mylogic here  
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Saml2Provider>().ToTable("Saml2ProviderConfigContext", schema: "config");
    }
}

Я хочу, чтобы внешние поставщики автоматически обновлялись на экране входа в систему при их обновлении в базе данных.Я также хочу загрузить информацию о внешнем провайдере через ConfigurationDbContext, если это возможно, поскольку имеет смысл быть там.

Существует два вопроса, расширяющих ConfigurationDbContext:

  1. Миграции donнеправильно построить:

    Невозможно создать объект типа 'IdSrvConfigurationDbContext'.Добавьте реализацию IDesignTimeDbContextFactory в проект или посмотрите https://go.microsoft.com/fwlink/?linkid=851728 для дополнительных шаблонов, поддерживаемых во время разработки.

  2. Я не могу получить доступ к расширенному контекстуот запуска правильно.Я не уверен, как правильно подключить его.

Я уверен, что есть правильный способ подключить его, расширив компоновщик опций Identity, но я понятия не имеюкак это сделатьЛюбая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Я нашел решение этой проблемы, где я мог бы динамически добавить схему в SchemeProvider.

Ссылка: Динамическое добавление поставщика проверки подлинности SAML2 с использованием Sustainsys.Saml2 в ASP.NET Core

https://github.com/aspnet/AuthSamples/blob/master/samples/DynamicSchemes/Controllers/AuthController.cs

Это метод вызова наконтроллер, который добавит схему.

[HttpGet]
    public async Task<IActionResult> Challenge(string provider, string returnUrl)
    {
        if (string.IsNullOrEmpty(returnUrl))
        {
            returnUrl = "~/";
        }

        // validate returnUrl - either it is a valid OIDC URL or back to a local page
        if (Url.IsLocalUrl(returnUrl) == false && interaction.IsValidReturnUrl(returnUrl) == false)
        {
            // user might have clicked on a malicious link - should be logged
            throw new Exception("invalid return URL");
        }

        if (provider == AccountOptions.WindowsAuthenticationSchemeName)
        {
            // windows authentication needs special handling
            return await ProcessWindowsLoginAsync(returnUrl);
        }
        else
        {
            // start challenge and roundtrip the return URL and scheme
            var props = new AuthenticationProperties
            {
                RedirectUri = Url.Action(nameof(Callback)),
                Items =
                {
                    { "returnUrl", returnUrl },
                    { "scheme", provider },
                },
            };

            // Checks to see if the scheme exists in the provider, then will add a new one if it's found in the database.
            await schemeProviderLoader.TryAddScheme(provider);
            return Challenge(props, provider);
        }
    }

, и это класс, который будет искать схему в схеме, и, если она не существует, он попытается добавить ее из БД.

/// <summary>
/// Helper class to dynamically add Saml2 Providers the SchemeProvider.
/// If the scheme is not found on the scheme provider it will look it up in the database and if found, will add it to the schemeprovider.
/// </summary>
public class SchemeProviderLoader
{
    private readonly ApplicationDbContext dbContext;
    private readonly IAuthenticationSchemeProvider schemeProvider;
    private readonly IOptionsMonitorCache<Saml2Options> optionsCache;
    private readonly ILogger logger;

    /// <summary>
    /// Initializes a new instance of the <see cref="SchemeProviderLoader"/> class.
    /// </summary>
    /// <param name="dbContext">Database context used to lookup providers.</param>
    /// <param name="schemeProvider">SchemeProvider to add the scheme to.</param>
    /// <param name="optionsCache">Options cache to add the scheme options to.</param>
    /// <param name="logger">Logger.</param>
    public SchemeProviderLoader(ApplicationDbContext dbContext, IAuthenticationSchemeProvider schemeProvider, IOptionsMonitorCache<Saml2Options> optionsCache, ILogger<SchemeProviderLoader> logger)
    {
        this.dbContext = dbContext;
        this.schemeProvider = schemeProvider;
        this.optionsCache = optionsCache;
        this.logger = logger;
    }

    /// <summary>
    /// Will dynamically add a scheme after startup.
    /// If the scheme is not found on the scheme provider it will look it up in the database and if found, will add it to the schemeprovider.
    /// </summary>
    /// <param name="scheme">The name of the identity provider to add.</param>
    /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation. True if the scheme was found or added. False if it was not found.</returns>
    public async Task<bool> TryAddScheme(string scheme)
    {
        if (await schemeProvider.GetSchemeAsync(scheme) == null)
        {
            // Lookup to see if the scheme has been added to the saml2providers since the app was last loaded.
            var saml2Provider = await dbContext.Saml2Providers.FindAsync(scheme);
            if (saml2Provider == null)
            {
                return false;
            }

            // Add the scheme.
            schemeProvider.AddScheme(new AuthenticationScheme(scheme, saml2Provider.IdpCaption, typeof(Saml2Handler)));

            // Add saml2 options to the options cache
            Saml2Options options = new Saml2Options();
            saml2Provider.GetSaml2Options(options);
            options.SPOptions.Logger = new AspNetCoreLoggerAdapter(logger);
            optionsCache.TryAdd(scheme, options);
        }

        return true;
    }
}
0 голосов
/ 08 февраля 2019

Независимо от того, как и где вы храните эту конфигурацию, она все еще используется только при запуске приложения.Дизайн стандартного промежуточного программного обеспечения, к сожалению, не способствует изменениям конфигурации во время выполнения.

Для этой работы мне пришлось изменить промежуточное программное обеспечение OIDC, которое могло бы принимать конфигурацию во время выполнения с помощью метода Challenge.Возможно, вам придется сделать это и для промежуточного программного обеспечения SAML.

...