【问题标题】:IdentityServer4 database migration issueIdentityServer4 数据库迁移问题
【发布时间】:2020-05-27 16:10:34
【问题描述】:

我正在使用 .net core 3.1 构建 identityserver4。我正在使用数据库迁移来构建数据库。我遇到的问题是播种方法。我的播种方法如下:

private void ClientSeed(ModelBuilder builder)
        {
            builder.Entity<ApiResource>()
               .HasData(
                   new ApiResource
                   {
                       Name = "PatientPortalAPI",
                       DisplayName = "Patient Portal API",

                       ApiSecrets =
                       {
                           new Secret("secret".Sha256())
                       },

                       Scopes =
                       {
                           new Scope()
                           {
                                 Name = StandardScopes.OfflineAccess,
                                 DisplayName = StandardScopes.OfflineAccess,
                                 Description = null,
                                 Required = false,
                                 Emphasize = false,
                                 ShowInDiscoveryDocument = true,
                           },
                           new Scope()
                           {
                                 Name = StandardScopes.OpenId,
                                 DisplayName = StandardScopes.OpenId,
                                 Description = null,
                                 Required = false,
                                 Emphasize = false,
                                 ShowInDiscoveryDocument = true,
                           }
                       }
                   }
               );

            builder.Entity<IdentityResource>().HasData(
                    new IdentityResource()
                    {
                        Enabled = true,
                        Name = "openid",
                        DisplayName = "Your user identifier",
                        Description = null,
                        Required = true,
                        Emphasize = false,
                        ShowInDiscoveryDocument = true,
                    },
                    new IdentityResource()
                    {
                        Enabled = true,
                        Name = "profile",
                        DisplayName = "User profile",
                        Description = "Your user profile information (first name, last name, etc.)",
                        Required = false,
                        Emphasize = true,
                        ShowInDiscoveryDocument = true,
                    });

            builder.Entity<Client>()
                .HasData(
                    new Client
                    {
                        ClientId = "t8agr5xKt4$3",
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },

                        AllowedScopes =
                        {
                            StandardScopes.OpenId,
                            StandardScopes.Profile,
                            StandardScopes.Email,
                            StandardScopes.Address,
                            "api1",
                            StandardScopes.OfflineAccess
                        },

                        AllowOfflineAccess = true,
                        RefreshTokenUsage = TokenUsage.ReUse,
                        RefreshTokenExpiration = TokenExpiration.Sliding,
                    });
        }

我在添加迁移时遇到的错误是:

System.InvalidOperationException: No suitable constructor found for entity type 'Claim'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'reader' in 'Claim(BinaryReader reader)'; cannot bind 'reader', 'subject' in 'Claim(BinaryReader reader, ClaimsIdentity subject)'; cannot bind 'type', 'value' in 'Claim(string type, string value)'; cannot bind 'type', 'value', 'valueType' in 'Claim(string type, string value, string valueType)'; cannot bind 'type', 'value', 'valueType', 'issuer' in 'Claim(string type, string value, string valueType, string issuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject', 'propertyKey', 'propertyValue' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)'; cannot bind 'other' in 'Claim(Claim other)'; cannot bind 'other', 'subject' in 'Claim(Claim other, ClaimsIdentity subject)'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
No suitable constructor found for entity type 'Claim'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'reader' in 'Claim(BinaryReader reader)'; cannot bind 'reader', 'subject' in 'Claim(BinaryReader reader, ClaimsIdentity subject)'; cannot bind 'type', 'value' in 'Claim(string type, string value)'; cannot bind 'type', 'value', 'valueType' in 'Claim(string type, string value, string valueType)'; cannot bind 'type', 'value', 'valueType', 'issuer' in 'Claim(string type, string value, string valueType, string issuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject', 'propertyKey', 'propertyValue' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)'; cannot bind 'other' in 'Claim(Claim other)'; cannot bind 'other', 'subject' in 'Claim(Claim other, ClaimsIdentity subject)'.

除去上面的种子方法,数据库迁移效果很好。一旦我在 ConfigurationDbContext 类的 OnModelCreating 方法中调用播种方法,它就会失败并出现上述错误。

谁能发现我哪里出错了???

期待您的所有回复。

提前致谢,

山姆

【问题讨论】:

  • 你确定在这里使用数据库实体类而不是框架模型类型吗?另外,我认为没有必要将这些范围添加到该 ApiResource。
  • 嗨,麦凯,非常感谢您的留言。我使用的是 IdentityServer4.EntityFramework.Entities 而不是模型类型。我正在尝试让刷新令牌工作。根据我的知识,我需要添加 offline_access 范围以获取刷新令牌
  • 我问的原因显然是在尝试使用标准框架声明类型做一些事情,而 EF 模型不会引用该类型。客户端配置上的 AllowOfflineAccess 是启用刷新令牌的东西。您还必须使用基于令牌端点的流程,例如混合或授权代码才能工作。
  • 你好 Mackie,我将 AllowOfflineAccess 设置为 true,并且使用授权码消费的令牌端点仍然不起作用。我收到 400 错误

标签: c# migration identityserver4 entity-framework-migrations asp.net-core-identity


【解决方案1】:

您应该在IdentityServer4.EntityFramework.Entities 上使用类型,您在代码中混合了模型和实体,尝试删除using IdentityServer4.Models; 以清楚地了解什么是实体和什么是模型。正确使用实体后,您会看到例如ApiResource 没有ApiSecrets 的属性,而是Secrets

还有另一种方法可以通过添加方法 ob startup.cs 来初始化 DB,例如:

private void InitializeDatabase(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

        var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in Config.Clients)
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.Ids)
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.Apis)
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

然后这样称呼它;

public void Configure(IApplicationBuilder app)
{
    // this will do the initial DB population
    InitializeDatabase(app);

    // the rest of the code that was already here
    // ...
}

阅读更多here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-25
    • 2020-11-05
    • 1970-01-01
    • 2012-05-20
    • 2021-12-01
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多