使用ASP.NET核心数据保护时出现异常



这似乎是随机的,但经常发生,但当我访问应用程序的主页时,有时会得到500分。我得到的例外:

An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information.
StackTrace:
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext) at Microsoft.AspNetCore.Authentication.SecureDataFormat`1.Protect(TData data, String purpose) at Microsoft.AspNetCore.Authentication.SecureDataFormat`1.Protect(TData data) at
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.WriteNonceCookie(String nonce) at
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties properties) at
Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.ChallengeAsync(AuthenticationProperties properties) at
Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties) at
Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result) at
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAlwaysRunResultFilters() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) at
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

我基本上遵循这里的指南:https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-2.2

我创建了这个扩展方法:

private static IServiceCollection AddDataProtection<TConfig, TLogger>(this IServiceCollection services, TConfig config) where TLogger : StandardLogger where TConfig : FrontEndAppConfigBase
{
if (Environment.MachineName.StartsWith("shal", StringComparison.InvariantCultureIgnoreCase))
return services;
if (!OAuthConfiguration.UseKeyVaultDataProtection) return services;
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var tokenCredential = new TokenCredential(azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/").Result);
var storageCredentials = new StorageCredentials(tokenCredential);
var storageAccount = new CloudStorageAccount(storageCredentials, "foocommonprotection", "core.windows.net", true);
services.AddDataProtection(options => { options.ApplicationDiscriminator = config.ApplicationName; })
.SetApplicationName(config.ApplicationName)
.PersistKeysToAzureBlobStorage(storageAccount, $"footokenprotectionkeys/{config.ServiceName ?? config.ApplicationName}{config.AppEnvironment}/keys.xml")
.ProtectKeysWithAzureKeyVault(new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)), $"{config.KeyVaultUrl}keys/dataProtectionKey");
return services;
}

是什么原因造成的?

我建议您更改实现,如下所示:

{
"DataProtection": {
"KeyVaultKeyId": "https://mykeyvaultname.vault.azure.net/keys/DataProtectionKey/bfc1bda979bc4081b89ab6f43bad12b8"
}
}
var kvClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(_tokenProvider.KeyVaultTokenCallback));
services.AddDataProtection()
.ProtectKeysWithAzureKeyVault(kvClient, settings.KeyVaultKeyId);

在启动.cs:

services.AddDataProtection()
.ProtectKeysWithAzureKeyVault(kvClient, settings.KeyVaultKeyId);
// Replicates PersistKeysToAzureBlobStorage
// There is no overload to give it the func it ultimately uses
// We need to do that so that we can get refreshed tokens when needed
services.Configure<KeyManagementOptions>(options =>
{
options.XmlRepository = new AzureBlobXmlRepository(() =>
{
// This func is called every time before getting the blob and before modifying the blob
// Get access token for Storage
// User / managed identity needs Blob Data Contributor on the Storage Account (container was not enough)
string accessToken = _tokenProvider.GetAccessTokenAsync("https://storage.azure.com/", tenantId: settings.AadTenantId)
.GetAwaiter()
.GetResult();
// Create blob reference with token
var tokenCredential = new TokenCredential(accessToken);
var storageCredentials = new StorageCredentials(tokenCredential);
var uri = new Uri($"https://{settings.StorageAccountName}.blob.core.windows.net/{settings.StorageKeyContainerName}/{settings.StorageKeyBlobName}");
// Note this func is expected to return a new instance on each call
var blob = new CloudBlockBlob(uri, storageCredentials);
return blob;
});
});

有关更多详细信息,您可以参考本文。

最新更新