我最近将 Azure 应用服务和 Azure SQL Server 配置为使用托管身份访问。应用服务具有系统分配的托管标识,并具有作为 SQL 数据库所有者的正确分配角色。当我将代码发布到应用程序服务时,它工作得很好并且能够访问数据库。
我的问题是,当通过 Visual Studio 在本地运行应用程序时,我无法通过应用程序连接到数据库。我的 Azure 帐户设置为 SQL Server 上的 Azure Active Directory 管理员,登录后我可以打开连接并通过 Azure Data Studio 运行查询。
我通过 Visual Studio 使用相同的帐户,甚至在“工具”->“选项”->“Azure 服务身份验证/帐户选择”下取消链接并重新链接它。但是当我尝试在本地运行该应用程序时,我收到错误
ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.
该错误并没有给我太多帮助,因为我不确定如何查看正在尝试进行身份验证的内容的完整视图。我没有使用任何代码来获取访问令牌,因为我只是让 Microsoft SQLClient 通过我的连接字符串为我获取它。
这是错误的完整堆栈跟踪,任何可以为我指明正确方向的内容将不胜感激。我的猜测是,这与 Visual Studios 有关,可能需要允许代表我获取访问令牌,但我想,既然我登录了我的 Azure 帐户,这可能并不重要。
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.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
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)
at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
Azure.RequestFailedException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
---> System.Net.Http.HttpRequestException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
---> System.Net.Sockets.SocketException (10051): A socket operation was attempted to an unreachable network.
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(HttpMessage message, Boolean async)
--- End of inner exception stack trace ---
at Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(HttpMessage message, Boolean async)
at Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline)
at Azure.Core.Pipeline.RequestActivityPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.RetryPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Identity.ImdsManagedIdentitySource.<AuthenticateAsync>d__15.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AuthenticateCoreAsync>d__17.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AppTokenProviderImpl>d__18.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<SendTokenRequestToProviderAsync>d__4.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<FetchNewAccessTokenAsync>d__3.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<ExecuteAsync>d__2.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.RequestBase.<RunAsync>d__12.MoveNext()
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.<ExecuteAsync>d__3.MoveNext()
at Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.<ExecuteAsync>d__0`1.MoveNext()
at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientCoreAsync>d__21.MoveNext()
at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientAsync>d__20.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AuthenticateAsync>d__16.MoveNext()
at Azure.Identity.ManagedIdentityCredential.<GetTokenImplAsync>d__16.MoveNext()
at
Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage)
at Azure.Identity.ManagedIdentityCredential.<GetTokenImplAsync>d__16.MoveNext()
at Azure.Identity.ManagedIdentityCredential.<GetTokenAsync>d__14.MoveNext()
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.<AcquireTokenAsync>d__17.MoveNext()
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.<>c__DisplayClass147_1.<<GetFedAuthToken>b__1>d.MoveNext()
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
相关连接DbContext信息。目前 DbContext 类使用 Microsoft.EntityFrameworkCore 版本 7.0.3
public class DbEntities: DbContext
{
public DbEntities() : base() { }
//All DbSet<...> classes here
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"));
}
}
相关 AppSettings JSON 文件
{
"ConnectionStrings": {
"DB_CONNECTION_STRING": "Server=tcp:MY-SERVER.database.windows.net;Initial Catalog=development;Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication=\"Active Directory Managed Identity\";"
},
}
通过使用
Authentication=\"Active Directory Managed Identity\"
,您将告诉您的应用程序仅使用托管身份验证。仅当您实际作为 Azure 资源运行时才能使用此功能。您无法对您的个人帐户使用托管身份验证。
通过使用 Active Directory Default
作为值,系统将尝试多种变体:
使用无密码和非交互式机制(包括托管标识、Visual Studio Code、Visual Studio、Azure CLI 等)对 Azure AD 身份进行身份验证。