OracleでIDS4を使用するために、カスタマイズされたIConfigurationDbContext
を作成しました。
public class IdentityConfigurationDbContext : DbContext, IConfigurationDbContext {
private readonly ConfigurationStoreOptions storeOptions;
public IdentityConfigurationDbContext(DbContextOptions<IdentityServerDbContext> options)
: base(options) {
}
public IdentityConfigurationDbContext(DbContextOptions<ConfigurationDbContext> options, ConfigurationStoreOptions storeOptions)
: base(options) {
this.storeOptions = storeOptions ?? throw new ArgumentNullException(nameof(storeOptions));
}
public DbSet<Client> Clients { get; set; }
public DbSet<IdentityResource> IdentityResources { get; set; }
public DbSet<ApiResource> ApiResources { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.ConfigureClientContext(storeOptions);
modelBuilder.ConfigureResourcesContext(storeOptions);
base.OnModelCreating(modelBuilder);
}
}
configureServiceの場合:
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddAspNetIdentity<ApplicationUser>();
また、次のようにコンテナに追加されるカスタムIClientStore
もあります。
services.AddScoped<IClientStore, ClientStore>();
IdentityConfigurationDbContext
Migrationを実行すると、次のエラーが発生します。
System.InvalidOperationException: No database provider has been configured for this DbContext.
私はこれをやってみました:
services.AddDbContext<IdentityConfigurationDbContext>(builder => builder.UseOracle(connectionString, options => {
options.MigrationsAssembly(migrationsAssembly);
options.MigrationsHistoryTable("EF_MIGRATION_HISTORY");
}));
これは、IDS4でカスタムdbcontextを使用する正しい方法ですか?この問題を修正し、移行作業を完了するにはどうすればよいですか?
私は別のアプローチを試しました。 IConfigurationDbContext
を実装する代わりに、IdentityServer4.EntityFramework.DbContexts.ConfigurationDbContext
から継承しました
public class CustomConfigurationDbContext : ConfigurationDbContext
{
public CustomConfigurationDbContext(DbContextOptions<ConfigurationDbContext> options,
ConfigurationStoreOptions storeOptions)
: base(options, storeOptions)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
//...
base.OnConfiguring(optionsBuilder);
}
}
}
そしてstartup.csで
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddConfigurationStore(
builder => builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(migrationsAssembly)))
.AddOperationalStore(
builder => builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(migrationsAssembly)))
.AddAspNetIdentity<ApplicationUser>();
それは魅力のように機能します。免責事項:これは私の考えではありません。その出所を思い出せません。
最近のリリースでは、Identityserverフレームワークは、構成ストア、操作ストアのカスタム実装をサポートしています。これは移行でも機能します
たとえば、以下を参照してください
public class CustomPersistsDbContext : DbContext, IPersistedGrantDbContext
{
}
OnModelCreating(ModelBuilder modelBuilder)で、リレーションを手動で追加する必要がありました。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Optional: The version of .NET Core, used by Ef Core Migration history table
modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
//.. Your custom code
//PersistentDbContext
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
{
b.Property<string>("UserCode")
.ValueGeneratedOnAdd()
.HasMaxLength(200);
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200);
b.Property<DateTime>("CreationTime");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000);
b.Property<string>("DeviceCode")
.IsRequired()
.HasMaxLength(200);
b.Property<DateTime?>("Expiration")
.IsRequired();
b.Property<string>("SubjectId")
.HasMaxLength(200);
b.HasKey("UserCode");
b.HasIndex("DeviceCode")
.IsUnique();
b.HasIndex("UserCode")
.IsUnique();
b.ToTable("DeviceCodes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
{
b.Property<string>("Key")
.HasMaxLength(200);
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200);
b.Property<DateTime>("CreationTime");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000);
b.Property<DateTime?>("Expiration");
b.Property<string>("SubjectId")
.HasMaxLength(200);
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50);
b.HasKey("Key");
b.HasIndex("SubjectId", "ClientId", "Type");
b.ToTable("PersistedGrants");
});
}
サービスの起動時
.AddOperationalStore<CustomPersistsDbContext>(options =>
別のデータベースを使用するように切り替えるために、カスタムConfigurationDbContext
またはイベントIDbContextFactory
を作成する必要はありません。 IdentityServer4.EntityFramework
バージョン2.3.2を使用すると、次のことができます。
namespace DL.STS.Host
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
string connectionString = _configuration.GetConnectionString("appDbConnection");
string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly
.GetName().Name;
services
.AddIdentityServer()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
// I made up this extension method "UseOracle",
// but this is where you plug your database in
builder.UseOracle(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
...;
...
}
...
}
}
ソリューションを適切にレイアウトし、構成ストアと運用ストア(およびIDユーザーストア)を独自のクラスライブラリ/アセンブリに分離したい場合はどうなりますか?
ドキュメントによると、-o
を使用して、出力移行フォルダーの宛先を指定できます。
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
しかし、移行を行うときに、誰がそのような長いパスを記憶/入力するのが好きですか?次に、次のように考えるかもしれません。IdentityServerから継承されたカスタムConfigurationDbContext
と、別のプロジェクトはどうでしょうか。
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Options;
using Microsoft.EntityFrameworkCore;
namespace DL.STS.Data.ConfigurationStore.EFCore
{
public class AppConfigurationDbContext : ConfigurationDbContext
{
public AppConfigurationDbContext(DbContextOptions<ConfigurationDbContext> options,
ConfigurationStoreOptions storeOptions) : base(options, storeOptions)
{
}
}
}
ここがトラブルに巻き込まれるところだと思います。 Add-Migration
を実行すると、次のいずれかに遭遇します。
タイプ
AppConfigurationDbContext
のオブジェクトを作成できません。設計時にサポートされるさまざまなパターンについては、 https://go.Microsoft.com/fwlink/?linkid=851728 を参照してください。
または
Microsoft.EntityFrameworkCore.DbContextOptions<IdentityServer4.EntityFramework.DbContexts.ConfigurationDbContext>
をアクティブ化しようとしているときに、タイプDL.STS.Data.ConfigurationStore.EFCore.AppConfigurationDbContext
のサービスを解決できません。
今のところ、それを修正する方法はないと思います。
実際には非常に簡単であることがわかりました。 IdentityServerから独自のDbContext
を継承することはできないようです。したがって、それを取り除き、その別のライブラリ/アセンブリに拡張メソッドを作成します。
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace DL.STS.Data.ConfigurationStore.EFCore.Extensions
{
public static class IdentityServerBuilderExtensions
{
public static IIdentityServerBuilder AddEFConfigurationStore(
this IIdentityServerBuilder builder, string connectionString)
{
string assemblyNamespace = typeof(IdentityServerBuilderExtensions)
.GetTypeInfo()
.Assembly
.GetName()
.Name;
builder.AddConfigurationStore(options =>
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString, optionsBuilder =>
optionsBuilder.MigrationsAssembly(assemblyNamespace)
)
);
return builder;
}
}
}
次に、WebプロジェクトのStartup.cs
で:
public void ConfigureServices(IServiceCollection services)
{
...
string connectionString = _configuration.GetConnectionString("appDbConnection");
services
.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddEFConfigurationStore(connectionString)
...;
...
}
そして、デフォルトのプロジェクトがその別個のライブラリ/アセンブリであるPM> Add-Migration AddConfigurationTables -Context ConfigurationDbContext
を実行すると、次のようになります。
IDbContextFactory
を追加すると、問題が修正されました。
public class IdentityConfigurationDbContextFactory : IDbContextFactory<IdentityConfigurationDbContext> {
public IdentityConfigurationDbContext Create(DbContextFactoryOptions options) {
var optionsBuilder = new DbContextOptionsBuilder<ConfigurationDbContext>();
var config = new ConfigurationBuilder()
.SetBasePath(options.ContentRootPath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{options.EnvironmentName}.json", true)
.Build();
optionsBuilder.UseOracle(config.GetConnectionString("DefaultConnection"));
return new IdentityConfigurationDbContext(optionsBuilder.Options, new ConfigurationStoreOptions());
}
}
これを行う最も簡単な方法は、以下のようにConfigurationDbContextのパラメーターTを使用することだと思います。それはネットコア3.0で私のために働きます
public class ConfigurationDataContext : ConfigurationDbContext<ConfigurationDataContext>
{
public ConfigurationDataContext(DbContextOptions<ConfigurationDataContext> options, ConfigurationStoreOptions storeOptions)
: base(options, storeOptions)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(MyConfigurationsAssemby).Assembly);
}
}