我们有一个使用 MI 连接到 Azure SQL 的应用程序服务。
自从我们迁移到使用 MI 以来,我们就看到了这个错误:
An unhandled exception occured while processing a job: Microsoft.Data.SqlClient.SqlException (0x80131904): Next reconnection attempt will exceed query timeout. Reconnection was terminated.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'. Token is expired.
at Microsoft.Data.ProviderBase.DbConnectionPool.CheckPoolBlockingPeriod(Exception e)
at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.ReplaceConnection(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
应用程序重新启动后错误消失,并且似乎在几天后再次出现。
我们有一个 DbConnectionInterceptor,它获取令牌作为 ConnectionOpening() 方法的一部分。
应用程序构建器初始化:
var applicationBuilder = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
.WithClientAssertion(new ManagedIdentityClientAssertion(managedIdentityClientId).GetSignedAssertion)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.WithAzureRegion(ConfidentialClientApplication.AttemptRegionDiscovery)
.Build();
从 ConnectionOpening 方法调用获取令牌方法:
private string GetAccessToken()
{
var applicationBuilder = _confidentialClientAppBuilder.GetConfidentialClientApp();
var scopes = new[] { "https://database.windows.net/.default" };
AuthenticationResult authenticationResult = Task.Run(async () => await applicationBuilder.AcquireTokenForClient(scopes).ExecuteAsync().ConfigureAwait(false)).GetAwaiter().GetResult();
return authenticationResult.AccessToken;
}
令牌刷新是否没有在内部处理?我们需要在这里做一些额外的事情吗? 我们有另一个不使用 DbContext 池的应用程序,它似乎工作正常。只有使用池的人才面临这个问题。任何见解都会有帮助。
令牌刷新是否没有在内部处理?我们需要在这里做些什么吗?
根据文档
类将令牌缓存在内存中,并在到期前从 Microsoft Entra ID 中检索它。您不需要任何自定义代码来刷新令牌。DefaultAzureCredential
这仅存在于
System.Data.SqlClient
(在 .NET Framework 上)中,在某些情况下,当连接池中的连接的令牌过期时,SqlClient 可能无法丢弃该连接并刷新令牌
使用
Microsoft.Data.SqlClient
此客户端通常可以更好地处理令牌过期和托管身份,并改进对 AAD 令牌刷新的支持。要解决代码中的问题,请添加此 NuGet 包:
Install-Package Microsoft.Data.SqlClient -Version 5.1.0
安装后,更新您的代码以使用
Microsoft.Data.SqlClient
请查看此文档以获取更多信息。