Добавление аутентификации сервера идентификации в приложение .NET Core 3 завершается ошибкой "Тип ключа не указан".

Я пытаюсь добавить аутентификацию сервера идентификации в проект .NET Core 3 API.

Я добавил этот код

public void ConfigureServices(IServiceCollection services)
{
    … 

    var identityBuilder = services.AddIdentityServer();

    identityBuilder.AddApiAuthorization<ApplicationUser, DbContext>();

    services
        .AddAuthentication()
        .AddIdentityServerJwt();

    var fileName = Path.Combine("Certificates", "certificatefile.pfx");
    var cert = new X509Certificate2(fileName, "veryDifficultPassword");
    identityBuilder.AddSigningCredential(cert);

    … 
}

А также:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    … 
    app.UseAuthentication();
    app.UseIdentityServer(); // <--- this line throws error.
    app.UseAuthorization();
    … 
}

В папке /Certificates есть файл, который правильно читается и загружается - я могу проверить переменную cert, и она выглядит правильно.

Все, что я пробовал до сих пор, заканчивается строкой app.UseIdentityServer();, взорванной:

System.InvalidOperationException: «Тип ключа не указан».

Какие-либо предложения?

Обновление: включая stacktrace

System.InvalidOperationException
  HResult=0x80131509
  Message=Key type not specified.
  Source=Microsoft.AspNetCore.ApiAuthorization.IdentityServer
  StackTrace:
   at Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.LoadKey()
   at Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.Configure(ApiAuthorizationOptions options)
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
   at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
   at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
   at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
   at Microsoft.Extensions.DependencyInjection.IdentityServerBuilderConfigurationExtensions.<>c.<AddClients>b__7_1(IServiceProvider sp)
   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.VisitRootCache(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.VisitDisposeCache(ServiceCallSite transientCallSite, 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.VisitDisposeCache(ServiceCallSite transientCallSite, 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.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.TestService(IServiceProvider serviceProvider, Type service, ILogger logger, String message, Boolean doThrow)
   at Microsoft.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.Validate(IApplicationBuilder app)
   at Microsoft.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.UseIdentityServer(IApplicationBuilder app, IdentityServerMiddlewareOptions options)
   at Boskapstorget.API.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in C:\Private\Kod\Boskapstorget\Backend\src\Boskapstorget.API\Startup.cs:line 86
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.<UseStartup>b__2(IApplicationBuilder app)
   at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__31.MoveNext()

comment
Я прочитал это, прежде чем опубликовать это, он кажется похожим, однако ответ, похоже, не относится к ядру asp.net (я пытался безрезультатно).   -  person JensB    schedule 27.09.2019
comment
app.UseAuthentication(); не требуется. Снимаем и проверяем. Он добавит его по умолчанию с UseIdentityServer();   -  person pavinan    schedule 27.09.2019
comment
Я удалил его, все та же ошибка. Интересно то, что в приложении-шаблоне angular это тоже с самого начала.   -  person JensB    schedule 27.09.2019
comment
Можете ли вы предоставить трассировку стека исключения? Я только что попробовал это с шаблоном, созданным с использованием dotnet new react -o reacttest -au Individual. Затем я создал файл pfx, экспортировав сертификат из своего хранилища сертификатов, и добавил строки кода, показанные в вашем вопросе. Я могу запустить приложение без исключений. Возможно, ваш файл pfx неверен?   -  person Richard    schedule 28.09.2019
comment
@Richard Я включил трассировку стека. Этот шаблон мне тоже подходит. Но я хочу включить это в существующее приложение. Я скопировал весь код, относящийся к этому, из шаблона, но мне должно быть что-то не хватает, так как он выдает эту ошибку каждый раз, когда я пытаюсь его запустить.   -  person JensB    schedule 28.09.2019


Ответы (1)


Я не думаю, что код, который вы добавили для установки сертификата подписи, вызвал проблему. Код в stacktrace выполняется, потому что identityBuilder.AddApiAuthorization<ApplicationUser, DbContext>(); вызывает AddSigningCredentials(), который в конечном итоге настраивает код для поиска в appsettings.json определения ключа Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials:

public SigningCredentials LoadKey()
{
    var key = new KeyDefinition();
    _configuration.Bind(key);
    switch (key.Type)
    {
        case KeySources.Development:
            var developmentKeyPath = Path.Combine(Directory.GetCurrentDirectory(), key.FilePath ?? DefaultTempKeyRelativePath);
            var createIfMissing = key.Persisted ?? true;
            _logger.LogInformation($"Loading development key at '{developmentKeyPath}'.");
            var developmentKey = new RsaSecurityKey(SigningKeysLoader.LoadDevelopment(developmentKeyPath, createIfMissing))
            {
                KeyId = "Development"
            };
            return new SigningCredentials(developmentKey, "RS256");
        case KeySources.File:
            var pfxPath = Path.Combine(Directory.GetCurrentDirectory(), key.FilePath);
            var pfxPassword = key.Password;
            var storageFlags = GetStorageFlags(key);
            _logger.LogInformation($"Loading certificate file at '{pfxPath}' with storage flags '{key.StorageFlags}'.");
            return new SigningCredentials(new X509SecurityKey(SigningKeysLoader.LoadFromFile(pfxPath, key.Password, storageFlags)), "RS256");
        case KeySources.Store:
            if (!Enum.TryParse<StoreLocation>(key.StoreLocation, out var storeLocation))
            {
                throw new InvalidOperationException($"Invalid certificate store location '{key.StoreLocation}'.");
            }
            _logger.LogInformation($"Loading certificate with subject '{key.Name}' in '{key.StoreLocation}\\{key.StoreName}'.");
            return new SigningCredentials(new X509SecurityKey(SigningKeysLoader.LoadFromStoreCert(key.Name, key.StoreName, storeLocation, GetCurrentTime())), "RS256");
        case null:
            throw new InvalidOperationException($"Key type not specified.");
        default:
            throw new InvalidOperationException($"Invalid key type '{key.Type ?? "(null)"}'.");
    }
}

Вы выбрали регистр null, потому что ваш файл appsettings.json или appsettings.Development.json не настраивает Key.

Я могу воспроизвести вашу проблему двумя способами:

Комментирование ключевой конфигурации в appsetting. Development .json

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "IdentityServer": {
    //"Key": {
    //  "Type": "Development"
    //}
  }
}

Предполагается, что вы запускаете \ отлаживаете в среде разработки.

введите описание изображения здесь

Второй способ воспроизведения - настроить для работы в производственной среде, которая не имеет определения Key по умолчанию в appsettings.json

введите описание изображения здесь

Я думаю, что решением вашей проблемы было бы определение файла сертификата в appsettings.json или appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "IdentityServer": {
    "Key": {
      "Type": "File",
      "FilePath": "Certificates\\certificatefile.pfx",
      "Password": "veryDifficultPassword"
    }
  }
}

и удалите этот код

var fileName = Path.Combine("Certificates", "certificatefile.pfx");
var cert = new X509Certificate2(fileName, "veryDifficultPassword");
identityBuilder.AddSigningCredential(cert);
person Richard    schedule 29.09.2019
comment
Это решило это. Большое спасибо за время и усилия, которые вы вложили в это. - person JensB; 29.09.2019
comment
Моя проблема заключалась в том, как вы заявили, ошибка в файле appsettings. - person JensB; 29.09.2019
comment
Привет, я поместил сертификат в App_Data, затем Key: {Type: File, FilePath: App_Data \\ my.pfx, Password: TTYYAYYAA} И я все еще получаю Internal.Cryptography.CryptoThrowHelper + WindowsCryptographicException: система не может найти указанный файл. \ R \ n Я использую общий хост (на моем компьютере он работает нормально) - person Cristovao Morgado; 03.12.2020