使用托管身份进行 SQL 访问 - 令牌过期

问题描述 投票:0回答:1

我们有一个使用 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 池的应用程序,它似乎工作正常。只有使用池的人才面临这个问题。任何见解都会有帮助。

c# azure-managed-identity sqlclient
1个回答
0
投票

令牌刷新是否没有在内部处理?我们需要在这里做些什么吗?

根据文档

DefaultAzureCredential
类将令牌缓存在内存中,并在到期前从 Microsoft Entra ID 中检索它。您不需要任何自定义代码来刷新令牌。

这仅存在于

System.Data.SqlClient
(在 .NET Framework 上)中,在某些情况下,当连接池中的连接的令牌过期时,SqlClient 可能无法丢弃该连接并刷新令牌

使用

Microsoft.Data.SqlClient
此客户端通常可以更好地处理令牌过期和托管身份,并改进对 AAD 令牌刷新的支持。要解决代码中的问题,请添加此 NuGet 包:

Install-Package Microsoft.Data.SqlClient -Version 5.1.0

安装后,更新您的代码以使用

Microsoft.Data.SqlClient

请查看此文档以获取更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.