.NET 7中DI注入DefaultAzureCredential时的认证异常问题
问题场景
在.NET 7环境下使用Azure SDK,遵循微软官方依赖注入指南,通过依赖注入(DI)实例化Azure客户端时,搭配DefaultAzureCredential和Azure CLI登录出现认证问题。
测试结果:
- 直接实例化ArmClient(传入DefaultAzureCredential)可正常获取订阅ID
- 通过DI容器获取的ArmClient会抛出网络不可达异常,尝试访问Azure元数据服务地址
169.254.169.254 - 将DefaultAzureCredential替换为AzureCliCredential后,DI方式可正常运行
复现代码
using Azure.Identity; using Azure.ResourceManager; using Microsoft.Extensions.Azure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddAzureClients(builder => { builder.UseCredential(new DefaultAzureCredential()); builder.AddClient<ArmClient, ArmClientOptions>((options, creds) => new ArmClient(creds)); }); }) .Build(); var armClient = new ArmClient(new DefaultAzureCredential()); var sub = await armClient.GetDefaultSubscriptionAsync(); Console.WriteLine("Sub ID from direct DefaultAzureCredential(): " + sub.Id); armClient = host.Services.GetRequiredService<ArmClient>(); sub = await armClient.GetDefaultSubscriptionAsync(); Console.WriteLine("Sub ID from DI: " + sub.Id);
错误日志
info: Azure.Core[1] Request [03e2d65f-5d81-4842-a5f5-df1a6fb1422b] GET http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=REDACTED Metadata:REDACTED x-ms-client-request-id:03e2d65f-5d81-4842-a5f5-df1a6fb1422b x-ms-return-client-request-id:true User-Agent:azsdk-net-Identity/1.8.2 (.NET 7.0.5; Microsoft Windows 10.0.22621) client assembly: Azure.Identity info: Azure.Core[18] Request [03e2d65f-5d81-4842-a5f5-df1a6fb1422b] exception Azure.RequestFailedException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
问题原因与解决方案
原因分析
DefaultAzureCredential会按固定顺序尝试多种认证方式,其中包含ManagedIdentityCredential(托管身份认证)。在DI场景下,托管身份的检测逻辑误将本地环境判定为Azure资源,优先尝试访问元数据服务,而本地无法连接该地址导致异常。直接实例化时的认证顺序或检测逻辑存在差异,优先使用了Azure CLI的凭证。
解决方案
方案1:禁用托管身份认证
实例化DefaultAzureCredential时,通过配置项排除ManagedIdentityCredential,避免不必要的元数据服务访问:
services.AddAzureClients(builder => { var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeManagedIdentityCredential = true }); builder.UseCredential(credential); builder.AddClient<ArmClient, ArmClientOptions>((options, creds) => new ArmClient(creds)); });
方案2:指定优先认证方式
如果仅需使用Azure CLI认证,可直接替换为AzureCliCredential;或调整DefaultAzureCredential的认证顺序,将AzureCliCredential放在最前面:
services.AddAzureClients(builder => { var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { CredentialChain = new List<TokenCredential> { new AzureCliCredential(), new VisualStudioCredential(), new VisualStudioCodeCredential() // 按需添加其他认证方式,排除ManagedIdentityCredential即可 } }); builder.UseCredential(credential); builder.AddClient<ArmClient, ArmClientOptions>((options, creds) => new ArmClient(creds)); });
补充说明
DefaultAzureCredential默认认证顺序为:
EnvironmentCredential → ManagedIdentityCredential → SharedTokenCacheCredential → VisualStudioCredential → VisualStudioCodeCredential → AzureCliCredential → AzurePowerShellCredential
本地开发时,建议根据需求调整认证选项,减少不必要的认证尝试,提升效率并避免异常。
内容的提问来源于stack exchange,提问作者Federico Rapetti

