【问题标题】:Cannot created the SignatureProvider, 'key.HasPrivateKey' is false无法创建 SignatureProvider,'key.HasPrivateKey' 为 false
【发布时间】:2018-06-22 04:47:20
【问题描述】:

我们使用 IdentityServer4("http://docs.identityserver.io/en/release/quickstarts/0_overview.html") 和 EntityFrameworkCore 来存储操作和配置数据。要添加签名凭据,我们使用 x509 自签名证书。我们使用以下命令创建 x509 自签名证书:makecert -r -pe -n "CN=CertName_IdentityServer" -b 01/01/2015 -e 01/01/2039 -eku 1.3.6.1.5.5.7.3.3 -sky signature -a sha256 -len 2048 identityserver.cer。并将此证书作为嵌入式源添加到解决方案中。 这是我们的 startup.cs 文件:

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IConfiguration>(Configuration);

        //connection string
        string connectionString = Configuration.GetConnectionString("IdentityServer");

        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        ConfigureSigningCerts(services);

        services.AddIdentityServer()
            // this adds the config data from DB (clients, resources)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder =>
                builder.UseSqlServer(connectionString,
                sql => sql.MigrationsAssembly(migrationsAssembly));
            }) // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder =>
                builder.UseSqlServer(connectionString,
            sql => sql.MigrationsAssembly(migrationsAssembly));

                // this enables automatic token cleanup. this is optional.
                options.EnableTokenCleanup = true;
                options.TokenCleanupInterval = 30;
            });
    }
private static void ConfigureSigningCerts(IServiceCollection services)
    {

        var assembly = typeof(Startup).GetTypeInfo().Assembly; 
        /*
        * IdentityServer.WebApi\
        *     Certificates\
        *         identityserver.cer
        * 
        * {assembly name}.{directory}.{file name}
        */
        using (Stream resource = assembly.GetManifestResourceStream("IdentityServer.WebApi.Certificates.identityserver.cer"))
        using (var reader = new BinaryReader(resource))
        {
            var signingCert = new X509Certificate2(reader.ReadBytes((int)resource.Length));


            var keys = new List<SecurityKey>();

            if (signingCert == null) throw new InvalidOperationException("No valid signing certificate could be found.");

            var signingCredential = new SigningCredentials(new X509SecurityKey(signingCert), "RS256");
            services.AddSingleton<ISigningCredentialStore>(new DefaultSigningCredentialsStore(signingCredential));

            var validationCredential = new SigningCredentials(new X509SecurityKey(signingCert), "RS256");
            keys.Add(validationCredential.Key);
            services.AddSingleton<IValidationKeysStore>(new DefaultValidationKeysStore(keys));
        }
    }

当我们在本地主机发现端点上执行应用程序时工作正常,但当调用connect/token 端点时,我们收到以下错误消息:

    crit: IdentityServer4.Hosting.IdentityServerMiddleware[0]
      Unhandled exception: System.InvalidOperationException: IDX10638: Cannot created the SignatureProvider, 'key.HasPrivateKey' is false, cannot create signatures. Key: Microsoft.IdentityModel.Tokens.X509SecurityKey.
         at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
         at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenCreationService.cs:line 209
         at IdentityServer4.Services.DefaultTokenCreationService.<CreateTokenAsync>d__4.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenCreationService.cs:line 67
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Services.DefaultTokenService.<CreateSecurityTokenAsync>d__9.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenService.cs:line 210
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<CreateAccessTokenAsync>d__14.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 313
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessTokenRequestAsync>d__13.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 249
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessAsync>d__7.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 84
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Endpoints.TokenEndpoint.<ProcessTokenRequestAsync>d__7.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Endpoints\TokenEndpoint.cs:line 98
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Endpoints.TokenEndpoint.<ProcessAsync>d__6.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Endpoints\TokenEndpoint.cs:line 70
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Hosting.IdentityServerMiddleware.<Invoke>d__3.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\IdentityServerMiddleware.cs:line 54
crit: IdentityServer4.Hosting.IdentityServerMiddleware[0]
      Unhandled exception: System.InvalidOperationException: IDX10638: Cannot created the SignatureProvider, 'key.HasPrivateKey' is false, cannot create signatures. Key: Microsoft.IdentityModel.Tokens.X509SecurityKey.
         at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
         at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenCreationService.cs:line 209
         at IdentityServer4.Services.DefaultTokenCreationService.<CreateTokenAsync>d__4.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenCreationService.cs:line 67
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Services.DefaultTokenService.<CreateSecurityTokenAsync>d__9.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Services\DefaultTokenService.cs:line 210
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<CreateAccessTokenAsync>d__14.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 313
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessTokenRequestAsync>d__13.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 249
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessAsync>d__7.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\ResponseHandling\TokenResponseGenerator.cs:line 84
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Endpoints.TokenEndpoint.<ProcessTokenRequestAsync>d__7.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Endpoints\TokenEndpoint.cs:line 98
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Endpoints.TokenEndpoint.<ProcessAsync>d__6.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Endpoints\TokenEndpoint.cs:line 70
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
         at IdentityServer4.Hosting.IdentityServerMiddleware.<Invoke>d__3.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\IdentityServerMiddleware.cs:line 54

【问题讨论】:

  • makecert 已被弃用。您可以使用的替代工具之一是 powershell New-SelfSignedCertificate 模块。 petri.com/create-self-signed-certificate-using-powershell 如果您运行它并且仍然收到证书错误,请在此处回复,我将继续分享我的进度/代码,因为我目前正在研究将自签名证书绑定到 ID4 并且还有一个方法从嵌入式资源加载证书。

标签: identityserver4


【解决方案1】:

如果您使用文件,您可能需要执行额外的步骤并分配密码以允许访问私钥。

这应该会有所帮助:How to create a self signed certificate with the private key inside in a file in one simple step?

另一种方法是在本地计算机证书存储中生成证书,然后通过证书管理 MMC 管理单元将其导出。

【讨论】:

    【解决方案2】:

    从 Powershell(以管理员身份运行 Powershell):

    $cert = New-SelfSignedCertificate -DnsName yourSiteHere.com -type Custom -CertStoreLocation cert:\localmachine\my -KeyExportPolicy Exportable
    

    使用上面的命令 Issuer 变成 yourSiteHere 并且到期日期是默认的一年。它还将具有长度为 2048 的 RSA 密钥。 然后,您可以使用 certmgr 实用程序导出证书(Powershell 中还有更多命令可以导出,我还没有使用过)。 有关详细信息,请参阅这些链接:

    https://www.petri.com/create-self-signed-certificate-using-powershell

    https://docs.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps

    现在,在 IdentityServer4 中,我扩展了 IIdentityServerBuilder 类以提供从该类型文件绑定证书的方法 - 很快,如果您有一个静态类,并且它的方法采用“this someClass”形式的参数,那么这是一个“扩展”。您可以扩展任何类,甚至是 C# 内部的那些标准类(如字符串等)。如果您这样做,当您在该类或该类型的变量之后键入句点时,您的方法也会出现 Intellisense。这意味着我可以在启动时从构建器访问我的方法(您只需在 Startup.cs 中将 using 放入扩展类的命名空间):

    public static class SigningCredentialExtension
    {
         public static IIdentityServerBuilder GetCertFromAzure(this IIdentityServerBuilder builder)
         {
               //Note:  in order for the certificate to be visible to the app, 
               //an application setting "WEBSITE_LOAD_CERTIFICATES" with the value 
               //of your SSL cert's thumbprint must be added to your IdentityServer
               //webapp on Azure.
               var thumbprint = "your cert's thumbprint";
    
               var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
               store.Open(OpenFlags.ReadOnly);
    
               var certs = store.Certificates.Find(X509FindType.FindByThumbprint, 
                        certThumbprint, true);
    
               if (certs.Count > 0)
               {
                    X509Certificate2 cert = 
                           new X509Certificate2(certs[0].Export(X509ContentType.Pfx,
                               "your cert's password"));
                    builder.AddSigningCredential(cert);
                    builder.AddValidationKey(cert);
               }
               return builder;
         }
    
         public static IIdentityServerBuilder GetCertFromEmbeddedProjectFile(
                       IIdentityServerBuilder builder)
         {
              var assembly = Assembly.GetExecutingAssembly();
              var fileName = "Your.Project.Namespace.FileName.fileExtension";
              using (Stream stream = assembly.GetManifestResourceStream(resourceName))
              {
                    Byte[] raw = new Byte[stream.Length];
    
                    for (Int32 i = 0; i < stream.Length; i++)
                    {
                        raw[i] = (Byte)stream.ReadByte();
                    }
                    X509Certificate2 cert = new X509Certificate2(raw, password);
                    builder.AddSigningCredential(cert);
                    builder.AddValidationKey(cert);
               }
               return builder;
         }
    }
    

    所以 - 在你的项目中包含上面的类,确保 Startup.cs 可以看到它(如果需要,包括一个 using),去掉你的 ConfigureSigningCerts() 方法,并在你的“services.AddIdentityServer()”行之后键入“。”您将在列表中看到扩展方法。使用你想要的方法。不需要指定参数,方法会自动获取builder。构建器将被返回用于后面的方法。

    【讨论】:

    • 要使 GetCertFromAzure 方法正常工作,您必须将 SSL 证书绑定到 Azure 上的 Web 应用(由受信任的证书颁发机构颁发)。
    • 使用上述方法,只需在 Startup 中的 builder 中调用上述方法之一,您一直在调用该方法来添加开发人员证书。如果证书过期,您可以对其进行调整以提供后备策略。
    猜你喜欢
    • 2020-12-13
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    • 2018-02-13
    • 2021-09-18
    • 2014-02-22
    • 2019-09-10
    • 1970-01-01
    相关资源
    最近更新 更多