Identityserver4 如何将自定义表添加到configurationDbContext?
我希望定制IdentityServer4,以便从数据库加载外部身份提供程序。我想扩展ConfigurationDBContext以包括Saml2Provider的数据库集。在我的启动中,我想自动添加Saml2Provider。理想情况下,我希望有一种简单的方法可以在idsvr4登录页面中刷新可用的提供商列表,而无需重新启动应用程序 我已经能够从DB加载我的Saml2Providers,并将它们注册为外部提供者。但是,这是使用ApplicationDbcontext,并且不会在每次请求idsvr时刷新它 这是我的configureServices,它正在使用ApplicationDbContext从数据库检索提供程序:Identityserver4 如何将自定义表添加到configurationDbContext?,identityserver4,entity-framework-migrations,sustainsys-saml2,Identityserver4,Entity Framework Migrations,Sustainsys Saml2,我希望定制IdentityServer4,以便从数据库加载外部身份提供程序。我想扩展ConfigurationDBContext以包括Saml2Provider的数据库集。在我的启动中,我想自动添加Saml2Provider。理想情况下,我希望有一种简单的方法可以在idsvr4登录页面中刷新可用的提供商列表,而无需重新启动应用程序 我已经能够从DB加载我的Saml2Providers,并将它们注册为外部提供者。但是,这是使用ApplicationDbcontext,并且不会在每次请求idsvr时
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时存在两个问题:
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");
}
}
迁移无法正确生成:
无法创建“IdSrvConfigurationDbContext”类型的对象。将“IDesignTimeDbContextFactory”的实现添加到项目中,或参阅以获取设计时支持的其他模式
我无法从启动时正确访问扩展上下文。我不知道如何正确地连接它
我确信通过扩展Identity options builder有一个正确的方法来连接这一点,但我不知道如何做到这一点。任何帮助都将不胜感激。无论您如何以及在何处存储该配置,它仍然只在应用程序启动时使用。不幸的是,标准中间件的设计不利于运行时配置的更改
为了实现这一点,我必须修改OIDC中间件,该中间件可以通过质询方法在运行时接受配置。您可能也必须为SAML中间件执行此操作。我找到了解决此问题的方法,可以在SchemeProvider中动态添加一个方案 参考: 这是控制器上的质询方法,将在方案中添加一个质询
[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);
}
}
这个类将在schemeprovider中查找scheme,如果它不存在,它将尝试从DB中添加它
/// <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;
}
}
只需分叉idsrv4 ef核心包并根据您的需要进行修改。