.NET Core X509Certificate2的用法(在Windows / IIS,Docker,Linux下)

mon*_*nty 7 c# x509certificate2 identityserver4 asp.net-core-2.1 .net-core-2.1

我确实在尝试长时间使用.NET Core API中的证书。

基本上,我需要在IIS和docker上运行的.NET Core Web API中使用它们。

我需要使用的证书用于:

Microsoft.AspNetCore.DataProtection

public void ConfigureServices(IServiceCollection services)
{
  services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(dataProtectionKeystorePath))
    .ProtectKeysWithCertificate
    (
      new X509Certificate2(dataProtectionCertificatePath, dataProtectionCertificateSecret)
    );
}
Run Code Online (Sandbox Code Playgroud)

Kestrel选项以设置SSL证书

public static IWebHost BuildWebHost(string[] args) =>
  WebHost.CreateDefaultBuilder(args)
    .UseKestrel
    (
      options =>
        {
          options.Listen(address, port, listenOptions =>
            {
              listenOptions.UseHttps(new X509Certificate2(sslCertificatePath, sslCertifciateSecret));
            }
          );
        }
      )
      // other setup
     ;
Run Code Online (Sandbox Code Playgroud)

IdentityServer4.SigningCredentials

注意:此代码可从VS2017开始在开发机上运行,​​但会在Windows 2008 R2 IIS测试服务器上引发这些异常。

services.AddIdentityServer()
  .AddSigningCredential
  (
    new X509Certificate2(tokenCertificatePath, tokenCertificatePassphrase)
  )
  // other setup
  ;
Run Code Online (Sandbox Code Playgroud)

这三个都意味着放置一个证书文件,使用构造函数加载它,传递密码,然后开始。

sarkasm>快乐,这很容易。<萨卡姆

因此,我创建了一个包含证书的certs子目录。添加了机密设置。验证所有值均已按预期加载/创建。验证文件位于预期位置并因此存在。简而言之:

string dataProtectionKeystorePath = System.Path.Combine(Environment.ContentRootPath, "keystore");
string dataProtectionCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "keystore.pfx");
string dataProtectionSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("keystoreSecret", null);

string tokenCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "token.pfx");
string tokenCertificateSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("tokenSecret", null);

string sslCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "ssl.pfx");
string sslCertificateSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("tokenSecret", null);
Run Code Online (Sandbox Code Playgroud)

他们说,让我们玩得开心。因此,我们开始进行部署。

我最终得到的是那些例外:

数据保护例外:

info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[58]
      Creating key {39560783-e349-475e-8e3f-748abb8c6c8b} with creation date 2018-11-16 08:01:49Z, activation date 2018-11-16 08:01:49Z, and expiration date 2019-02-14 08:01:49Z.
info: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[39]
      Writing data to file '[intentionally removed for post]'.
fail: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[24]
      An exception occurred while processing the key element '<key id="39560783-e349-475e-8e3f-748abb8c6c8b" version="1" />'.
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist
   at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
   at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
   at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
   at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.GetKeyFromCert(EncryptedKey encryptedKey, KeyInfoX509Data keyInfo)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.DecryptEncryptedKey(EncryptedKey encryptedKey)
   at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
   at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[12]
      Key {39560783-e349-475e-8e3f-748abb8c6c8b} is ineligible to be the default key because its CreateEncryptor method failed.
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist
   at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
   at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
   at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
   at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.GetKeyFromCert(EncryptedKey encryptedKey, KeyInfoX509Data keyInfo)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.DecryptEncryptedKey(EncryptedKey encryptedKey)
   at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
   at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyDescriptorDelegate>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.get_Descriptor()
   at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey key)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver.CanCreateAuthenticatedEncryptor(IKey key)
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[12]
      Key {39560783-e349-475e-8e3f-748abb8c6c8b} is ineligible to be the default key because its CreateEncryptor method failed.
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist
   at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
   at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
   at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
   at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.GetKeyFromCert(EncryptedKey encryptedKey, KeyInfoX509Data keyInfo)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.EncryptedXmlWithCertificateKeys.DecryptEncryptedKey(EncryptedKey encryptedKey)
   at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
   at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyDescriptorDelegate>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Lazy`1.CreateValue()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.get_Descriptor()
   at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey key)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver.CanCreateAuthenticatedEncryptor(IKey key)
Run Code Online (Sandbox Code Playgroud)

Identity Server 4签名凭据的例外

Application startup exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at AuthServer.Startup.ConfigureServices(IServiceCollection services) in [intentionally removed for post]\Startup.cs:line 136
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6]
      Application startup exception
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at AuthServer.Startup.ConfigureServices(IServiceCollection services) in [intentionally removed for post]\Startup.cs:line 136
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Run Code Online (Sandbox Code Playgroud)

SSL证书的例外

Unhandled Exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at AuthServer.Program.<>c.<BuildWebHost>b__1_3(ListenOptions listenOptions) in [intentionally removed for post]\Program.cs:line 58
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.Listen(IPEndPoint endPoint, Action`1 configure)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.Listen(IPAddress address, Int32 port, Action`1 configure)
   at Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure(String name, TOptions 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)
--- End of stack trace from previous location where exception was thrown ---
   at System.Lazy`1.CreateValue()
   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.AspNetCore.Server.Kestrel.Core.KestrelServer.CreateServiceContext(IOptions`1 options, ILoggerFactory loggerFactory)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer..ctor(IOptions`1 options, ITransportFactory transportFactory, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   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.ServiceProviderEngine.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureServer()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.StartAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token, String shutdownMessage)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
   at MyProject.Program.Main(String[] args) in [intentionally removed for post]\Program.cs:line 47
Run Code Online (Sandbox Code Playgroud)

几个月以来,面对这个证书例外,我反复尝试了很多,然后再次面对这个例外(根据google结果,在github上问的问题等。)我想到我错过了一些导入。

我尝试使用StorageFlags,但未找到一种(组合)工作方式。

这些项目应在Windows(IIS),泊坞窗上运行,并且可能在Linux(ubuntu,debian)上运行一次。这就是为什么我们决定将证书放置在(跨多个实例安装的)子目录中的原因。因此,我发现建议将证书安装到Microsoft证书存储中的帖子将不起作用。在docker和linux上怎么可能呢?

由于我倾向于使用的所有证书都受到影响,因此我意识到问题可能是我在如何使用证书方面存在重大误会。

谁能帮助我弄清我错过的重点,并最终获得证书运行?我需要配置一些东西吗?如果可以的话?


只是一些调查摘要:

我确定文件存在吗:是的,因为否则将是例外

System.Security.Cryptography.CryptographicException: System cannot find specified file.
Run Code Online (Sandbox Code Playgroud)

我确定密码正确吗:是的,因为否则例外是

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The specified network password is not correct.
Run Code Online (Sandbox Code Playgroud)

文件权限:感谢CheshireCat提醒我。在Windows Server 2008 R2 IIS 7.5上,我检查了用户DefaultAppPool的certs子目录的文件许可权(以为现在是另一个用户unitl)。如以下链接所示,已将对certs子目录的完全访问文件权限授予用户DefaultAppPool 。

通常,IS4签名凭据异常在应用程序启动时发生。使用X509KeyStorageFlags.MachineKeySet不会在启动时抛出,而是显示登录窗口并在登录后抛出。没有返回令牌,而是创建了会话,因此用户可以修改ASP NET身份帐户设置。

证书过期:证书可以过期。数据保护似乎不检查到期日期,因此即使证书过期也可以使用。仍然可以使用Identi

Che*_*Cat 6

我在IS4项目上运行的实际代码是这样的:

X509Certificate2 certificate = null;

// Load certificate from Certificate Store using the configured Thumbprint
using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, appConfiguration.CertificateThumbprint, false);

    if (certificates.Count > 0)
        certificate = certificates[0];
}

// Fallback to load certificate from local file
if (certificate == null)
{
    string path = Path.Combine("C:\\Certificates", appConfiguration.CertificateFilename);

    try
    {
        certificate = new X509Certificate2(path, "CertificateSecret123$");
        logger.LogInformation($"Found from file {certificate.Thumbprint}");
    }
    catch (Exception ex)
    {
        logger.LogError(ex, $"Certificate file error {path}");
        certificate = null;
    }
}

if (certificate == null)
    throw new Exception($"Certificate {appConfiguration.CertificateThumbprint} not found.");

builder.AddSigningCredential(certificate);
Run Code Online (Sandbox Code Playgroud)

如果更改指纹以强制代码从本地文件中查找证书,则会得到预期的结果:

结果

更新2018/11/19

我纠正了代码中的错误,原因是在未找到证书文件的情况下,X509Certificate2类构造函数会引发异常。因此,实际上,永远不会到达if (certificate == null)行之后的先前控件certificate = new X509Certificate2...。

使代码起作用的步骤是:

  1. 创建证书并将其放在目录中
  2. 为运行代码的用户检查文件夹的目录权限。
    • 如果您在开发计算机上,请检查运行VS的用户是否有权访问放置文件的目录。
    • 如果您使用的是IIS,请检查AppPool承载应用程序的主机以及执行该应用程序的用户。它需要对证书目录具有权限。
  3. 使用示例代码从文件中加载证书。确保路径正确无误。
  4. 使用指纹从商店加载证书。要获取证书指纹,您可以:
    • 使用PowerShell命令Get-ChildItem -path cert:\LocalMachine\My在您注册证书的商店中指定正确的位置。
    • 通过右键单击.pfx文件->打开->在MMC控制台中找到文件,使用Windows资源管理器->双击它->详细信息->指纹。重要说明:当从预览文本框中处理/粘贴“指纹”值时,Windows中存在一个众所周知的丑陋错误。粘贴值时,将在指纹的开头添加一个HIDDEN字符。因此,请先在文本编辑器上将其复制/粘贴,然后通过使用箭头键移动到第一个字符附近来进行检查。另请参见本。