无效操作异常:未指定密钥类型。Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.LoadKey()

25

摘要

我尝试使用带有身份验证功能的基本.NET Core React应用程序发布,但是在使用IdentityServer时出现错误。这是使用dotnet new react --auth Individual、.Net Core 3.0 Preview5并遵循此处此处的说明。

我已通过TLS / SSL设置上传了PFX。我还确保证书可以在我的开发环境中工作,并发现GetMyX509Certificate返回了该证书。

在Startup.cs中的Configure中运行app.UseIdentityServer()时引起问题的代码似乎是:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        //...

        Log.Information("Configure - running app.Use: Authentication, IdentityServer");

       Log.Information("Configure - running app.Use: Authentication");
        app.UseAuthentication();
        Log.Information("Configure - running app.Use: IdentityServer");
        app.UseIdentityServer();

        //CODE DOESN'T MAKE IT HERE!!!
        Log.Information("Configure - running app.UseMvc");

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action=Index}/{id?}");
        });

        Log.Information("Configure - running app.UseSpa");

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseReactDevelopmentServer(npmScript: "start");
            }
        });

        Log.Information("Configure - Done!");
    }

错误信息

当我设置ASPNETCORE_DETAILEDERRORS = true时,出现了以下错误:

InvalidOperationException: Key type not specified

Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.LoadKey()
    Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.Configure(ApiAuthorizationOptions options)
    Microsoft.Extensions.Options.OptionsFactory<TOptions>.Create(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>+<>c__DisplayClass5_0.<Get>b__0()
    System.Lazy<T>.ViaFactory(LazyThreadSafetyMode mode)
    System.Lazy<T>.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
    System.Lazy<T>.CreateValue()
    System.Lazy<T>.get_Value()
    Microsoft.Extensions.Options.OptionsCache<TOptions>.GetOrAdd(string name, Func<TOptions> createOptions)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.Get(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.get_Value()
    Microsoft.Extensions.DependencyInjection.IdentityServerBuilderConfigurationExtensions+<>c.<AddClients>b__7_1(IServiceProvider sp)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine+<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
    Microsoft.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.TestService(IServiceProvider serviceProvider, Type service, ILogger logger, string message, bool doThrow)
    Microsoft.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.Validate(IApplicationBuilder app)
    Microsoft.AspNetCore.Builder.IdentityServerApplicationBuilderExtensions.UseIdentityServer(IApplicationBuilder app)
    ReactWithAuth.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in Startup.cs
    System.RuntimeMethodHandle.InvokeMethod(object target, object[] arguments, Signature sig, bool constructor, bool wrapExceptions)
    System.Reflection.RuntimeMethodInfo.Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
    Microsoft.AspNetCore.Hosting.Internal.ConfigureBuilder.Invoke(object instance, IApplicationBuilder builder)
    Microsoft.AspNetCore.Hosting.Internal.ConfigureBuilder+<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
    Microsoft.AspNetCore.Hosting.Internal.ConventionBasedStartup.Configure(IApplicationBuilder app)
    Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter+<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
    Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter+<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
    Microsoft.AspNetCore.HostFilteringStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
    Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
        Microsoft.Extensions.DependencyInjection.IdentityServerBuilderExtensionsCrypto.AddSigningCredential(IIdentityServerBuilder builder, X509Certificate2 certificate)
        Projects.Startup.ConfigureServices(IServiceCollection services) in Startup.cs
        System.RuntimeMethodHandle.InvokeMethod(object target, object[] arguments, Signature sig, bool constructor, bool wrapExceptions)
        System.Reflection.RuntimeMethodInfo.Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        Microsoft.AspNetCore.Hosting.Internal.ConfigureServicesBuilder.InvokeCore(object instance, IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.ConfigureServicesBuilder+<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection)
        Microsoft.AspNetCore.Hosting.Internal.StartupLoader+ConfigureServicesDelegateBuilder<TContainerBuilder>+<>c__DisplayClass15_0.<BuildStartupServicesFilterPipeline>g__RunPipeline|0(IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.ConfigureServicesBuilder.Invoke(object instance, IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.ConfigureServicesBuilder+<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.StartupLoader+ConfigureServicesDelegateBuilder<TContainerBuilder>+<>c__DisplayClass14_0.<ConfigureServices>g__ConfigureServicesWithContainerConfiguration|0(IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
        Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
        Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
        Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

我尝试过的事情

目前解决方案不多。IdentityServer4只在授权类型方面讨论了类型,但这似乎是在此之前。


在应用程序服务中处理证书的更好方法,您可以参考此文章:https://learn.microsoft.com/en-us/azure/app-service/app-service-web-ssl-cert-load。您还可以将证书存储在Azure密钥保管库中。 - Thomas
4个回答

44

正如您已经回答的那样 - 解决方案是将以下设置添加到appsettings.json中的"IdentityServer"括号内。这跟随了"Clients"元素:

对于文件

 "IdentityServer": {
    "Key": {
      "Type": "File",
      "FilePath": "C:\cert.pfx",
      "Password": "password123"
    }
  }

仅供开发使用(显然不能在生产环境中使用)

 "IdentityServer": {
    "Key": {
      "Type": "Development"
    }
  }

供商店使用

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

链接


4
我和我的同事们试图创建一个概念验证并让它运行起来,所以我们只需在我们的身份服务器配置中添加"Key":{"Type":"Development"}。这很顺利地完成了任务。 - Akshay Gaur

16

解决方法是将以下设置添加到appsettings.json中,放在“IdentityServer”括号内。这个紧随着“Clients”元素:

"Solution is to add the following settings into appsettings.json, within the "IdentityServer" brackets. This followed the "Clients" element:"

  "IdentityServer": { 
    "Key": {
      "Type": "Store",
      "StoreName": "My",
      "StoreLocation": "CurrentUser",
      "Name": "CN=**WHATEVER NAME YOU USED AS THE DISTINGUISHED SUBJECT FOR YOUR CERT**"
    }

这遵循此处的指示。请注意,这是使用OpenSSL创建的自签名证书,在文章中进行了操作。


你好,我想问一下,在你的设置中是否也遵循了这篇文章中“在Identity Server 4中使用证书”的部分:https://benjii.me/2017/06/creating-self-signed-certificate-identity-server-azure/?还是只是创建了证书,上传到私有存储区,并确保你的applicationsettings.json文件正确? - Tom
据我所记,当我使用IdentityServer时是这样的。 然而,当我不再需要IS时,我注释掉了证书功能。 希望有帮助。 - user
2
如果我使用Linux,这会是什么样子? - Marko Prcać
1
在Azure AppService Linux中使用Key Type文件,如下所示:"Type": "File", "FilePath": "/var/ssl/private/THUMBPRINT.p12", "Password": ""。也可以在此处查看:https://learn.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code#load-certificate-in-linux-apps - levitatejay

1
{
  "ConnectionStrings": {
    "DefaultConnection": ""
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "IdentityServer": {
    "Clients": {
      "Project01": {
        "Profile": "IdentityServerSPA"
      }
    },
    "Key": {
      "Type": "Development"
    }
  },
  "AllowedHosts": "*"
}

0
从上述代码中,我推测下面这行代码引起了空指针异常。
.AddSigningCredential(cert);

因为 **cert** 为空,这归结于你的方法 GetMyX509Certificate

try
        {
            System.Diagnostics.Trace.TraceInformation($"HELLO! TRYING TO GET THE CERTIFICATE");
            return new X509Certificate2(File.ReadAllBytes(pfxFilePath), password, sFlags);
        }
        catch (PlatformNotSupportedException ex)
        {
            System.Diagnostics.Trace.TraceError($"HELLO! {ex.Message}");
            if(sFlags.HasFlag(X509KeyStorageFlags.EphemeralKeySet))
            {
                return GetMyX509Certificate(pfxFilePath,password,X509KeyStorageFlags.MachineKeySet);
            } else 
            {
                return null;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.TraceError($"HELLO! {ex.Message}");
            return null;
        }

由于您的代码没有抛出 **PlatformNotSupportedException** 类型的异常,所以它肯定会抛出通用异常,这将在最后一行被捕获。

 catch (Exception ex)
        {
            System.Diagnostics.Trace.TraceError($"HELLO! {ex.Message}");
            return null;
        }

从这里返回 null,内部会给出实际的错误。

我不明白为什么你不能使用 KUDU,但如果我是你,我建议你使用一些日志记录库启用信息记录,例如文件系统记录或使用自定义遥测的应用程序洞察。

希望能有所帮助。


嗨,Mohit,感谢回复。我已经更新了帖子 - 证书似乎正在工作,因为日志记录已经开始工作(Kudu也是如此)。问题似乎要么出在app.UseAuthentication()上,要么出在app.UseIdentityServer()上。 - user

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接