C# Connect to Ravendb keeps failing with error: This server requires client certificate for authentication, but none was provided by the client

C# Connect to Ravendb keeps failing with error: This server requires client certificate for authentication, but none was provided by the client

无论我尝试什么,在新的 .net 5 API 项目中我无法连接到 RavenDB。它给我一个错误:

This server requires client certificate for authentication, but none was provided by the client.

我连接数据库的方式:

byte[] certificateBytes = _certificateProvider.GetCertificate("CERT-NAME").Result;
string passphrase = _secretProvider.GetSecret("CERT-PASSPHRASE").Result;
X509Certificate2 certificate = new X509Certificate2(certificateBytes, passphrase);

var documentStore = new DocumentStore()
{
    Urls = new[] { databaseOptions.DbUrl },
    Conventions =
    {
        UseOptimisticConcurrency = true,
        FindCollectionName = findCollectionName
    },
    Database = "DBNAME",
    Certificate = certificate,
}.Initialize();

证书提供者和机密提供者从 Azure Key Vault 中获取数据。我验证了 X509Certificate,它与我在 RavenDB 的管理面板中获得的指纹相同。这样就正确加载了。此外,该证书对所请求的数据库

具有read/write 权限

但是当我执行以下操作时:

using (IAsyncDocumentSession session = documentStore.OpenAsyncSession())
{
    var entity = await session.Query<EntityDTO>()
        .SingleOrDefaultAsync();
}

然后我得到以下错误:

This server requires client certificate for authentication, but none was provided by the client.

这是在初始化文档存储时提供的证书。任何人都知道如何继续这个,因为 RavenCloud 没有提供比这更多的信息吗?

在另一个项目(.net core 3.1)中,具有相同证书的相同代码有效。但是在 .net 5 的发行说明中找不到任何可能导致此问题的内容。

您需要加载带有 MachineKeySet 标志的证书。

X509Certificate2 certificate = new X509Certificate2(certificateBytes, passphrase, X509KeyStorageFlags.MachineKeySet);

这将解决 Azure 中的问题,但您的本地开发机器在此更改后可能会出现问题。您需要允许用户 运行 RavenDB 完全访问本地计算机上的 MachineKeySet 文件夹。

"C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys"

另请注意,如果您之后不处理证书,私钥会堆积在该文件夹中(每次 X509Certificate2 构造函数打开证书时都会将一个密钥写入该文件夹)。

在 RavenDB 论坛中@iftah 回复说由于私钥,您应该将存储标志设置为 MachineKeySet。

虽然我不是这种情况,但它给了我一个检查的方向。我正在使用 CertificateClient 和 GetCertificateAsync 从 Azure Key Vault 加载证书。这只会为您提供 public 键。所以从来没有私钥。

借助此 post:。我发现我可以将 SecretClient 与 GetSecretAsync 一起使用。然后使用 Convert.FromBase64String() 并返回私钥。

所以对于那些有类似问题的人。请在加载证书时验证您是否拥有私钥。我的新密码:

byte[] certificateBytes = Convert.FromBase64String(_secretProvider.GetSecret("CERT-NAME").Result);
X509Certificate2 certificate = new X509Certificate2(certificateBytes, string.Empty);

var documentStore = new DocumentStore()
{
    Urls = new[] { databaseOptions.DbUrl },
    Conventions =
    {
        UseOptimisticConcurrency = true,
        FindCollectionName = findCollectionName
    },
    Database = "DBNAME",
    Certificate = certificate,
}.Initialize();

如果你想让证书像上面@iftah 所建议的那样在 Azure 上运行,请不要忘记按以下方式加载你的证书:

X509Certificate2 certificate = new X509Certificate2(certificateBytes, string.Empty, X509KeyStorageFlags.MachineKeySet);