private static bool IsDatabaseProvider(
            ModelBuilder modelBuilder,
            IdentityServerModelBuilderConfigurationOptions options,
            params EfCoreDatabaseProvider[] providers)
        {
            foreach (var provider in providers)
            {
                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql ||
                    modelBuilder.GetDatabaseProvider() == provider)
                {
                    return(true);
                }
            }

            return(false);
        }
示例#2
0
        public static void ConfigureIdentityServer(
            this ModelBuilder builder,
            Action <IdentityServerModelBuilderConfigurationOptions> optionsAction = null)
        {
            Check.NotNull(builder, nameof(builder));

            var options = new IdentityServerModelBuilderConfigurationOptions(
                AbpIdentityServerDbProperties.DbTablePrefix,
                AbpIdentityServerDbProperties.DbSchema
                );

            optionsAction?.Invoke(options);

            builder.Entity <Client>(client =>
            {
                client.ToTable(options.TablePrefix + "Clients", options.Schema);

                client.ConfigureFullAuditedAggregateRoot();

                client.Property(x => x.ClientId).HasMaxLength(ClientConsts.ClientIdMaxLength).IsRequired();
                client.Property(x => x.ProtocolType).HasMaxLength(ClientConsts.ProtocolTypeMaxLength).IsRequired();
                client.Property(x => x.ClientName).HasMaxLength(ClientConsts.ClientNameMaxLength);
                client.Property(x => x.ClientUri).HasMaxLength(ClientConsts.ClientUriMaxLength);
                client.Property(x => x.LogoUri).HasMaxLength(ClientConsts.LogoUriMaxLength);
                client.Property(x => x.Description).HasMaxLength(ClientConsts.DescriptionMaxLength);
                client.Property(x => x.FrontChannelLogoutUri).HasMaxLength(ClientConsts.FrontChannelLogoutUriMaxLength);
                client.Property(x => x.BackChannelLogoutUri).HasMaxLength(ClientConsts.BackChannelLogoutUriMaxLength);
                client.Property(x => x.ClientClaimsPrefix).HasMaxLength(ClientConsts.ClientClaimsPrefixMaxLength);
                client.Property(x => x.PairWiseSubjectSalt).HasMaxLength(ClientConsts.PairWiseSubjectSaltMaxLength);
                client.Property(x => x.UserCodeType).HasMaxLength(ClientConsts.UserCodeTypeMaxLength);

                client.HasMany(x => x.AllowedScopes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.ClientSecrets).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.AllowedGrantTypes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.AllowedCorsOrigins).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.RedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.PostLogoutRedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.IdentityProviderRestrictions).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.Claims).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                client.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ClientId).IsRequired();

                client.HasIndex(x => x.ClientId);
            });

            builder.Entity <ClientGrantType>(grantType =>
            {
                grantType.ToTable(options.TablePrefix + "ClientGrantTypes", options.Schema);

                grantType.HasKey(x => new { x.ClientId, x.GrantType });

                grantType.Property(x => x.GrantType).HasMaxLength(ClientGrantTypeConsts.GrantTypeMaxLength).IsRequired();
            });

            builder.Entity <ClientRedirectUri>(redirectUri =>
            {
                redirectUri.ToTable(options.TablePrefix + "ClientRedirectUris", options.Schema);

                redirectUri.HasKey(x => new { x.ClientId, x.RedirectUri });

                redirectUri.Property(x => x.RedirectUri).HasMaxLength(ClientRedirectUriConsts.RedirectUriMaxLength).IsRequired();
            });

            builder.Entity <ClientPostLogoutRedirectUri>(postLogoutRedirectUri =>
            {
                postLogoutRedirectUri.ToTable(options.TablePrefix + "ClientPostLogoutRedirectUris", options.Schema);

                postLogoutRedirectUri.HasKey(x => new { x.ClientId, x.PostLogoutRedirectUri });

                postLogoutRedirectUri.Property(x => x.PostLogoutRedirectUri).HasMaxLength(ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLength).IsRequired();
            });

            builder.Entity <ClientScope>(scope =>
            {
                scope.ToTable(options.TablePrefix + "ClientScopes", options.Schema);

                scope.HasKey(x => new { x.ClientId, x.Scope });

                scope.Property(x => x.Scope).HasMaxLength(ClientScopeConsts.ScopeMaxLength).IsRequired();
            });

            builder.Entity <ClientSecret>(secret =>
            {
                secret.ToTable(options.TablePrefix + "ClientSecrets", options.Schema);

                secret.HasKey(x => new { x.ClientId, x.Type, x.Value });

                secret.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
                secret.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired();
                secret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
            });

            builder.Entity <ClientClaim>(claim =>
            {
                claim.ToTable(options.TablePrefix + "ClientClaims", options.Schema);

                claim.HasKey(x => new { x.ClientId, x.Type, x.Value });

                claim.Property(x => x.Type).HasMaxLength(ClientClaimConsts.TypeMaxLength).IsRequired();
                claim.Property(x => x.Value).HasMaxLength(ClientClaimConsts.ValueMaxLength).IsRequired();
            });

            builder.Entity <ClientIdPRestriction>(idPRestriction =>
            {
                idPRestriction.ToTable(options.TablePrefix + "ClientIdPRestrictions", options.Schema);

                idPRestriction.HasKey(x => new { x.ClientId, x.Provider });

                idPRestriction.Property(x => x.Provider).HasMaxLength(ClientIdPRestrictionConsts.ProviderMaxLength).IsRequired();
            });

            builder.Entity <ClientCorsOrigin>(corsOrigin =>
            {
                corsOrigin.ToTable(options.TablePrefix + "ClientCorsOrigins", options.Schema);

                corsOrigin.HasKey(x => new { x.ClientId, x.Origin });

                corsOrigin.Property(x => x.Origin).HasMaxLength(ClientCorsOriginConsts.OriginMaxLength).IsRequired();
            });

            builder.Entity <ClientProperty>(property =>
            {
                property.ToTable(options.TablePrefix + "ClientProperties", options.Schema);

                property.HasKey(x => new { x.ClientId, x.Key });

                property.Property(x => x.Key).HasMaxLength(ClientPropertyConsts.KeyMaxLength).IsRequired();
                property.Property(x => x.Value).HasMaxLength(ClientPropertyConsts.ValueMaxLength).IsRequired();
            });

            builder.Entity <PersistedGrant>(grant =>
            {
                grant.ToTable(options.TablePrefix + "PersistedGrants", options.Schema);

                grant.ConfigureExtraProperties();

                grant.Property(x => x.Key).HasMaxLength(PersistedGrantConsts.KeyMaxLength).ValueGeneratedNever();
                grant.Property(x => x.Type).HasMaxLength(PersistedGrantConsts.TypeMaxLength).IsRequired();
                grant.Property(x => x.SubjectId).HasMaxLength(PersistedGrantConsts.SubjectIdMaxLength);
                grant.Property(x => x.ClientId).HasMaxLength(PersistedGrantConsts.ClientIdMaxLength).IsRequired();
                grant.Property(x => x.CreationTime).IsRequired();
                grant.Property(x => x.Data).HasMaxLength(PersistedGrantConsts.DataMaxLength).IsRequired();

                grant.HasKey(x => x.Key); //TODO: What about Id!!!

                grant.HasIndex(x => new { x.SubjectId, x.ClientId, x.Type });
                grant.HasIndex(x => x.Expiration);
            });

            builder.Entity <IdentityResource>(identityResource =>
            {
                identityResource.ToTable(options.TablePrefix + "IdentityResources", options.Schema);

                identityResource.ConfigureFullAuditedAggregateRoot();

                identityResource.Property(x => x.Name).HasMaxLength(IdentityResourceConsts.NameMaxLength).IsRequired();
                identityResource.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength);
                identityResource.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength);
                identityResource.Property(x => x.Properties)
                .HasConversion(
                    d => JsonConvert.SerializeObject(d, Formatting.None),
                    s => JsonConvert.DeserializeObject <Dictionary <string, string> >(s)
                    );

                identityResource.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
            });

            builder.Entity <IdentityClaim>(claim =>
            {
                claim.ToTable(options.TablePrefix + "IdentityClaims", options.Schema);

                claim.HasKey(x => new { x.IdentityResourceId, x.Type });

                claim.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiResource>(apiResource =>
            {
                apiResource.ToTable(options.TablePrefix + "ApiResources", options.Schema);

                apiResource.ConfigureFullAuditedAggregateRoot();

                apiResource.Property(x => x.Name).HasMaxLength(ApiResourceConsts.NameMaxLength).IsRequired();
                apiResource.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength);
                apiResource.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength);
                apiResource.Property(x => x.Properties)
                .HasConversion(
                    d => JsonConvert.SerializeObject(d, Formatting.None),
                    s => JsonConvert.DeserializeObject <Dictionary <string, string> >(s)
                    );

                apiResource.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                apiResource.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                apiResource.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
            });

            builder.Entity <ApiSecret>(apiSecret =>
            {
                apiSecret.ToTable(options.TablePrefix + "ApiSecrets", options.Schema);

                apiSecret.HasKey(x => new { x.ApiResourceId, x.Type, x.Value });

                apiSecret.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
                apiSecret.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired();
                apiSecret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
            });

            builder.Entity <ApiResourceClaim>(apiClaim =>
            {
                apiClaim.ToTable(options.TablePrefix + "ApiClaims", options.Schema);

                apiClaim.HasKey(x => new { x.ApiResourceId, x.Type });

                apiClaim.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiScope>(apiScope =>
            {
                apiScope.ToTable(options.TablePrefix + "ApiScopes", options.Schema);

                apiScope.HasKey(x => new { x.ApiResourceId, x.Name });

                apiScope.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
                apiScope.Property(x => x.DisplayName).HasMaxLength(ApiScopeConsts.DisplayNameMaxLength);
                apiScope.Property(x => x.Description).HasMaxLength(ApiScopeConsts.DescriptionMaxLength);

                apiScope.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => new { x.ApiResourceId, x.Name }).IsRequired();
            });

            builder.Entity <ApiScopeClaim>(apiScopeClaim =>
            {
                apiScopeClaim.ToTable(options.TablePrefix + "ApiScopeClaims", options.Schema);

                apiScopeClaim.HasKey(x => new { x.ApiResourceId, x.Name, x.Type });

                apiScopeClaim.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
                apiScopeClaim.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
            });
        }
        public static void ConfigureIdentityServer(
            this ModelBuilder builder,
            Action <IdentityServerModelBuilderConfigurationOptions> optionsAction = null)
        {
            Check.NotNull(builder, nameof(builder));

            var options = new IdentityServerModelBuilderConfigurationOptions(
                AbpIdentityServerDbProperties.DbTablePrefix,
                AbpIdentityServerDbProperties.DbSchema
                );

            optionsAction?.Invoke(options);

            #region Client

            builder.Entity <Client>(b =>
            {
                b.ToTable(options.TablePrefix + "Clients", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.ClientId).HasMaxLength(ClientConsts.ClientIdMaxLength).IsRequired();
                b.Property(x => x.ProtocolType).HasMaxLength(ClientConsts.ProtocolTypeMaxLength).IsRequired();
                b.Property(x => x.ClientName).HasMaxLength(ClientConsts.ClientNameMaxLength);
                b.Property(x => x.ClientUri).HasMaxLength(ClientConsts.ClientUriMaxLength);
                b.Property(x => x.LogoUri).HasMaxLength(ClientConsts.LogoUriMaxLength);
                b.Property(x => x.Description).HasMaxLength(ClientConsts.DescriptionMaxLength);
                b.Property(x => x.FrontChannelLogoutUri).HasMaxLength(ClientConsts.FrontChannelLogoutUriMaxLength);
                b.Property(x => x.BackChannelLogoutUri).HasMaxLength(ClientConsts.BackChannelLogoutUriMaxLength);
                b.Property(x => x.ClientClaimsPrefix).HasMaxLength(ClientConsts.ClientClaimsPrefixMaxLength);
                b.Property(x => x.PairWiseSubjectSalt).HasMaxLength(ClientConsts.PairWiseSubjectSaltMaxLength);
                b.Property(x => x.UserCodeType).HasMaxLength(ClientConsts.UserCodeTypeMaxLength);
                b.Property(x => x.AllowedIdentityTokenSigningAlgorithms).HasMaxLength(ClientConsts.AllowedIdentityTokenSigningAlgorithms);

                b.HasMany(x => x.AllowedScopes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.ClientSecrets).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.AllowedGrantTypes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.AllowedCorsOrigins).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.RedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.PostLogoutRedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.IdentityProviderRestrictions).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.Claims).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ClientId).IsRequired();

                b.HasIndex(x => x.ClientId);
            });

            builder.Entity <ClientGrantType>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientGrantTypes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.GrantType });

                b.Property(x => x.GrantType).HasMaxLength(ClientGrantTypeConsts.GrantTypeMaxLength).IsRequired();
            });

            builder.Entity <ClientRedirectUri>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientRedirectUris", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.RedirectUri });

                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
                {
                    ClientRedirectUriConsts.RedirectUriMaxLengthValue = 300;
                }

                b.Property(x => x.RedirectUri).HasMaxLength(ClientRedirectUriConsts.RedirectUriMaxLengthValue).IsRequired();
            });

            builder.Entity <ClientPostLogoutRedirectUri>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientPostLogoutRedirectUris", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.PostLogoutRedirectUri });

                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
                {
                    ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLengthValue = 300;
                }

                b.Property(x => x.PostLogoutRedirectUri)
                .HasMaxLength(ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLengthValue)
                .IsRequired();
            });

            builder.Entity <ClientScope>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientScopes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Scope });

                b.Property(x => x.Scope).HasMaxLength(ClientScopeConsts.ScopeMaxLength).IsRequired();
            });

            builder.Entity <ClientSecret>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientSecrets", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(ClientSecretConsts.TypeMaxLength).IsRequired();
                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
                {
                    ClientSecretConsts.ValueMaxLength = 300;
                }
                b.Property(x => x.Value).HasMaxLength(ClientSecretConsts.ValueMaxLength).IsRequired();
                b.Property(x => x.Description).HasMaxLength(ClientSecretConsts.DescriptionMaxLength);
            });

            builder.Entity <ClientClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(ClientClaimConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.Value).HasMaxLength(ClientClaimConsts.ValueMaxLength).IsRequired();
            });

            builder.Entity <ClientIdPRestriction>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientIdPRestrictions", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Provider });

                b.Property(x => x.Provider).HasMaxLength(ClientIdPRestrictionConsts.ProviderMaxLength).IsRequired();
            });

            builder.Entity <ClientCorsOrigin>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientCorsOrigins", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Origin });

                b.Property(x => x.Origin).HasMaxLength(ClientCorsOriginConsts.OriginMaxLength).IsRequired();
            });

            builder.Entity <ClientProperty>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientProperties", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Key, x.Value });

                b.Property(x => x.Key).HasMaxLength(ClientPropertyConsts.KeyMaxLength).IsRequired();
                b.Property(x => x.Value).HasMaxLength(ClientPropertyConsts.ValueMaxLength).IsRequired();
            });

            #endregion

            #region IdentityResource

            builder.Entity <IdentityResource>(b =>
            {
                b.ToTable(options.TablePrefix + "IdentityResources", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Name).HasMaxLength(IdentityResourceConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength);

                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
                b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
            });

            builder.Entity <IdentityResourceClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "IdentityResourceClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.IdentityResourceId, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <IdentityResourceProperty>(b =>
            {
                b.ToTable(options.TablePrefix + "IdentityResourceProperties", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.IdentityResourceId, x.Key, x.Value });

                b.Property(x => x.Key).HasMaxLength(IdentityResourcePropertyConsts.KeyMaxLength).IsRequired();
                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
                {
                    IdentityResourcePropertyConsts.ValueMaxLength = 300;
                }
                b.Property(x => x.Value).HasMaxLength(IdentityResourcePropertyConsts.ValueMaxLength).IsRequired();
            });

            #endregion

            #region ApiResource

            builder.Entity <ApiResource>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResources", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Name).HasMaxLength(ApiResourceConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength);
                b.Property(x => x.AllowedAccessTokenSigningAlgorithms).HasMaxLength(ApiResourceConsts.AllowedAccessTokenSigningAlgorithmsMaxLength);

                b.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                b.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
            });

            builder.Entity <ApiResourceSecret>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResourceSecrets", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(ApiResourceSecretConsts.TypeMaxLength).IsRequired();

                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
                {
                    ApiResourceSecretConsts.ValueMaxLength = 300;
                }
                b.Property(x => x.Value).HasMaxLength(ApiResourceSecretConsts.ValueMaxLength).IsRequired();

                b.Property(x => x.Description).HasMaxLength(ApiResourceSecretConsts.DescriptionMaxLength);
            });

            builder.Entity <ApiResourceClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResourceClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiResourceScope>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResourceScopes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Scope });

                b.Property(x => x.Scope).HasMaxLength(ApiResourceScopeConsts.ScopeMaxLength).IsRequired();
            });

            builder.Entity <ApiResourceProperty>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResourceProperties", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Key, x.Value });

                b.Property(x => x.Key).HasMaxLength(ApiResourcePropertyConsts.KeyMaxLength).IsRequired();
                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
                {
                    ApiResourcePropertyConsts.ValueMaxLength = 300;
                }
                b.Property(x => x.Value).HasMaxLength(ApiResourcePropertyConsts.ValueMaxLength).IsRequired();
            });

            #endregion

            #region ApiScope

            builder.Entity <ApiScope>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiScopes", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(ApiScopeConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(ApiScopeConsts.DescriptionMaxLength);

                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiScopeId).IsRequired();
                b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ApiScopeId).IsRequired();
            });

            builder.Entity <ApiScopeClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiScopeClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiScopeId, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiScopeProperty>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiScopeProperties", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiScopeId, x.Key, x.Value });

                b.Property(x => x.Key).HasMaxLength(ApiScopePropertyConsts.KeyMaxLength).IsRequired();
                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
                {
                    ApiScopePropertyConsts.ValueMaxLength = 300;
                }
                b.Property(x => x.Value).HasMaxLength(ApiScopePropertyConsts.ValueMaxLength).IsRequired();
            });

            #endregion

            #region PersistedGrant

            builder.Entity <PersistedGrant>(b =>
            {
                b.ToTable(options.TablePrefix + "PersistedGrants", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Key).HasMaxLength(PersistedGrantConsts.KeyMaxLength).ValueGeneratedNever();
                b.Property(x => x.Type).HasMaxLength(PersistedGrantConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.SubjectId).HasMaxLength(PersistedGrantConsts.SubjectIdMaxLength);
                b.Property(x => x.SessionId).HasMaxLength(PersistedGrantConsts.SessionIdMaxLength);
                b.Property(x => x.ClientId).HasMaxLength(PersistedGrantConsts.ClientIdMaxLength).IsRequired();
                b.Property(x => x.Description).HasMaxLength(PersistedGrantConsts.DescriptionMaxLength);
                b.Property(x => x.CreationTime).IsRequired();

                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
                {
                    PersistedGrantConsts.DataMaxLengthValue = 10000; //TODO: MySQL accepts 20.000. We can consider to change in v3.0.
                }

                b.Property(x => x.Data).HasMaxLength(PersistedGrantConsts.DataMaxLengthValue).IsRequired();

                b.HasKey(x => x.Key); //TODO: What about Id!!!

                b.HasIndex(x => new { x.SubjectId, x.ClientId, x.Type });
                b.HasIndex(x => new { x.SubjectId, x.SessionId, x.Type });
                b.HasIndex(x => x.Expiration);
            });

            #endregion

            #region DeviceFlowCodes

            builder.Entity <DeviceFlowCodes>(b =>
            {
                b.ToTable(options.TablePrefix + "DeviceFlowCodes", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.DeviceCode).HasMaxLength(DeviceFlowCodesConsts.DeviceCodeMaxLength).IsRequired();
                b.Property(x => x.UserCode).HasMaxLength(DeviceFlowCodesConsts.UserCodeMaxLength).IsRequired();
                b.Property(x => x.SubjectId).HasMaxLength(DeviceFlowCodesConsts.SubjectIdMaxLength);
                b.Property(x => x.SessionId).HasMaxLength(DeviceFlowCodesConsts.SessionIdMaxLength);
                b.Property(x => x.ClientId).HasMaxLength(DeviceFlowCodesConsts.ClientIdMaxLength).IsRequired();
                b.Property(x => x.Description).HasMaxLength(DeviceFlowCodesConsts.DescriptionMaxLength);
                b.Property(x => x.CreationTime).IsRequired();
                b.Property(x => x.Expiration).IsRequired();

                if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
                {
                    DeviceFlowCodesConsts.DataMaxLength = 10000; //TODO: MySQL accepts 20.000. We can consider to change in v3.0.
                }
                b.Property(x => x.Data).HasMaxLength(DeviceFlowCodesConsts.DataMaxLength).IsRequired();

                b.HasIndex(x => new { x.UserCode });
                b.HasIndex(x => x.DeviceCode).IsUnique();
                b.HasIndex(x => x.Expiration);
            });

            #endregion
        }
        public static void ConfigureIdentityServer(
            this ModelBuilder builder,
            Action <IdentityServerModelBuilderConfigurationOptions> optionsAction = null)
        {
            Check.NotNull(builder, nameof(builder));

            var options = new IdentityServerModelBuilderConfigurationOptions(
                AbpIdentityServerDbProperties.DbTablePrefix,
                AbpIdentityServerDbProperties.DbSchema
                );

            optionsAction?.Invoke(options);

            builder.Entity <Client>(b =>
            {
                b.ToTable(options.TablePrefix + "Clients", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.ClientId).HasMaxLength(ClientConsts.ClientIdMaxLength).IsRequired();
                b.Property(x => x.ProtocolType).HasMaxLength(ClientConsts.ProtocolTypeMaxLength).IsRequired();
                b.Property(x => x.ClientName).HasMaxLength(ClientConsts.ClientNameMaxLength);
                b.Property(x => x.ClientUri).HasMaxLength(ClientConsts.ClientUriMaxLength);
                b.Property(x => x.LogoUri).HasMaxLength(ClientConsts.LogoUriMaxLength);
                b.Property(x => x.Description).HasMaxLength(ClientConsts.DescriptionMaxLength);
                b.Property(x => x.FrontChannelLogoutUri).HasMaxLength(ClientConsts.FrontChannelLogoutUriMaxLength);
                b.Property(x => x.BackChannelLogoutUri).HasMaxLength(ClientConsts.BackChannelLogoutUriMaxLength);
                b.Property(x => x.ClientClaimsPrefix).HasMaxLength(ClientConsts.ClientClaimsPrefixMaxLength);
                b.Property(x => x.PairWiseSubjectSalt).HasMaxLength(ClientConsts.PairWiseSubjectSaltMaxLength);
                b.Property(x => x.UserCodeType).HasMaxLength(ClientConsts.UserCodeTypeMaxLength);

                b.HasMany(x => x.AllowedScopes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.ClientSecrets).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.AllowedGrantTypes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.AllowedCorsOrigins).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.RedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.PostLogoutRedirectUris).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.IdentityProviderRestrictions).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.Claims).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
                b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ClientId).IsRequired();

                b.HasIndex(x => x.ClientId);
            });

            builder.Entity <ClientGrantType>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientGrantTypes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.GrantType });

                b.Property(x => x.GrantType).HasMaxLength(ClientGrantTypeConsts.GrantTypeMaxLength).IsRequired();
            });

            builder.Entity <ClientRedirectUri>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientRedirectUris", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.RedirectUri });

                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
                {
                    b.Property(x => x.RedirectUri).HasMaxLength(300).IsRequired();
                }
                else
                {
                    b.Property(x => x.RedirectUri).HasMaxLength(ClientRedirectUriConsts.RedirectUriMaxLength).IsRequired();
                }
            });

            builder.Entity <ClientPostLogoutRedirectUri>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientPostLogoutRedirectUris", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.PostLogoutRedirectUri });

                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
                {
                    b.Property(x => x.PostLogoutRedirectUri).HasMaxLength(300).IsRequired();
                }
                else
                {
                    b.Property(x => x.PostLogoutRedirectUri).HasMaxLength(ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLength).IsRequired();
                }
            });

            builder.Entity <ClientScope>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientScopes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Scope });

                b.Property(x => x.Scope).HasMaxLength(ClientScopeConsts.ScopeMaxLength).IsRequired();
            });

            builder.Entity <ClientSecret>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientSecrets", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();

                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
                {
                    b.Property(x => x.Value).HasMaxLength(300).IsRequired();
                }
                else
                {
                    b.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired();
                }

                b.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
            });

            builder.Entity <ClientClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(ClientClaimConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.Value).HasMaxLength(ClientClaimConsts.ValueMaxLength).IsRequired();
            });

            builder.Entity <ClientIdPRestriction>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientIdPRestrictions", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Provider });

                b.Property(x => x.Provider).HasMaxLength(ClientIdPRestrictionConsts.ProviderMaxLength).IsRequired();
            });

            builder.Entity <ClientCorsOrigin>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientCorsOrigins", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Origin });

                b.Property(x => x.Origin).HasMaxLength(ClientCorsOriginConsts.OriginMaxLength).IsRequired();
            });

            builder.Entity <ClientProperty>(b =>
            {
                b.ToTable(options.TablePrefix + "ClientProperties", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ClientId, x.Key });

                b.Property(x => x.Key).HasMaxLength(ClientPropertyConsts.KeyMaxLength).IsRequired();
                b.Property(x => x.Value).HasMaxLength(ClientPropertyConsts.ValueMaxLength).IsRequired();
            });

            builder.Entity <PersistedGrant>(b =>
            {
                b.ToTable(options.TablePrefix + "PersistedGrants", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Key).HasMaxLength(PersistedGrantConsts.KeyMaxLength).ValueGeneratedNever();
                b.Property(x => x.Type).HasMaxLength(PersistedGrantConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.SubjectId).HasMaxLength(PersistedGrantConsts.SubjectIdMaxLength);
                b.Property(x => x.ClientId).HasMaxLength(PersistedGrantConsts.ClientIdMaxLength).IsRequired();
                b.Property(x => x.CreationTime).IsRequired();

                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
                {
                    b.Property(x => x.Data).HasMaxLength(10000).IsRequired();
                }
                else
                {
                    b.Property(x => x.Data).HasMaxLength(PersistedGrantConsts.DataMaxLength).IsRequired();
                }

                b.HasKey(x => x.Key); //TODO: What about Id!!!

                b.HasIndex(x => new { x.SubjectId, x.ClientId, x.Type });
                b.HasIndex(x => x.Expiration);
            });

            builder.Entity <IdentityResource>(b =>
            {
                b.ToTable(options.TablePrefix + "IdentityResources", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Name).HasMaxLength(IdentityResourceConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength);
                b.Property(x => x.Properties)
                .HasConversion(new AbpJsonValueConverter <Dictionary <string, string> >())
                .Metadata.SetValueComparer(new AbpDictionaryValueComparer <string, string>());

                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
            });

            builder.Entity <IdentityClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "IdentityClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.IdentityResourceId, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiResource>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiResources", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.Name).HasMaxLength(ApiResourceConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength);
                b.Property(x => x.Properties)
                .HasConversion(new AbpJsonValueConverter <Dictionary <string, string> >())
                .Metadata.SetValueComparer(new AbpDictionaryValueComparer <string, string>());

                b.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                b.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
            });

            builder.Entity <ApiSecret>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiSecrets", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Type, x.Value });

                b.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);

                if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
                {
                    b.Property(x => x.Value).HasMaxLength(300).IsRequired();
                }
                else
                {
                    b.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired();
                }
            });

            builder.Entity <ApiResourceClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
            });

            builder.Entity <ApiScope>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiScopes", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Name });

                b.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(ApiScopeConsts.DisplayNameMaxLength);
                b.Property(x => x.Description).HasMaxLength(ApiScopeConsts.DescriptionMaxLength);

                b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => new { x.ApiResourceId, x.Name }).IsRequired();
            });

            builder.Entity <ApiScopeClaim>(b =>
            {
                b.ToTable(options.TablePrefix + "ApiScopeClaims", options.Schema);

                b.ConfigureByConvention();

                b.HasKey(x => new { x.ApiResourceId, x.Name, x.Type });

                b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
                b.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
            });

            builder.Entity <DeviceFlowCodes>(b =>
            {
                b.ToTable(options.TablePrefix + "DeviceFlowCodes", options.Schema);

                b.ConfigureByConvention();

                b.Property(x => x.DeviceCode).HasMaxLength(200).IsRequired();
                b.Property(x => x.UserCode).HasMaxLength(200).IsRequired();
                b.Property(x => x.SubjectId).HasMaxLength(200);
                b.Property(x => x.ClientId).HasMaxLength(200).IsRequired();
                b.Property(x => x.Expiration).IsRequired();
                b.Property(x => x.Data).HasMaxLength(50000).IsRequired();

                b.HasIndex(x => new { x.UserCode }).IsUnique();
                b.HasIndex(x => x.DeviceCode).IsUnique();
                b.HasIndex(x => x.Expiration);
            });
        }