BotFramework的AspNet.WebApi集成库无法使用用户托管标识
ASP.NET Web API下Bot Framework适配用户托管标识的解决方案
问题场景:基于ASP.NET Web API构建的Bot应用,使用
Microsoft.Bot.Builder.Integration.AspNet.WebApi库,配置用户托管标识后出现clientSecret不能为空的异常,默认多租户密码模式可正常运行,但缺少Web API版本的托管标识适配示例。
1. 添加必要NuGet包
引入Azure.Identity包以使用托管标识凭证:
Install-Package Azure.Identity
2. 自定义CredentialProvider
替代默认的ConfigurationCredentialProvider,返回托管标识的客户端ID和租户ID,且不提供客户端密码:
using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using System.Threading.Tasks; public class ManagedIdentityCredentialProvider : ICredentialProvider { private readonly IConfiguration _configuration; public ManagedIdentityCredentialProvider(IConfiguration configuration) { _configuration = configuration; } public Task<string> GetAppIdAsync() { return Task.FromResult(_configuration["MicrosoftAppId"]); } public Task<string> GetAppPasswordAsync() { // 用户托管标识无需客户端密码,返回null return Task.FromResult<string>(null); } public Task<string> GetTenantIdAsync() { return Task.FromResult(_configuration["MicrosoftAppTenantId"]); } public Task<bool> IsAuthenticationDisabledAsync() { return Task.FromResult(false); } }
3. 自定义AppCredentials
继承MicrosoftAppCredentials,使用ManagedIdentityCredential获取令牌,替代原有的客户端密码认证逻辑:
using Azure.Identity; using Microsoft.Bot.Connector.Authentication; using System.Threading; using System.Threading.Tasks; public class ManagedIdentityAppCredentials : MicrosoftAppCredentials { private readonly ManagedIdentityCredential _managedIdentityCredential; private readonly string _tenantId; public ManagedIdentityAppCredentials(string appId, string tenantId) : base(appId, null, tenantId) { _tenantId = tenantId; _managedIdentityCredential = new ManagedIdentityCredential(clientId: appId); } public override async Task<string> GetTokenAsync(string audience, CancellationToken cancellationToken = default) { // 构造Bot Framework的令牌请求范围 var scope = $"{audience}/.default"; var tokenResult = await _managedIdentityCredential.GetTokenAsync( new TokenRequestContext(new[] { scope }) { TenantId = _tenantId }, cancellationToken); return tokenResult.Token; } }
4. 自定义BotFrameworkHttpAdapter
重写GetAppCredentialsAsync方法,使用自定义的托管标识凭证:
using Microsoft.Bot.Builder.Integration.AspNet.WebApi; using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using System.Threading.Tasks; public class ManagedIdentityBotFrameworkHttpAdapter : BotFrameworkHttpAdapter { private readonly IConfiguration _configuration; public ManagedIdentityBotFrameworkHttpAdapter(ICredentialProvider credentialProvider, IConfiguration configuration) : base(credentialProvider) { _configuration = configuration; } protected override async Task<AppCredentials> GetAppCredentialsAsync(string appId, System.Threading.CancellationToken cancellationToken) { var tenantId = await CredentialProvider.GetTenantIdAsync(); return new ManagedIdentityAppCredentials(appId, tenantId); } }
5. 更新依赖注入配置
替换原有的凭证提供器和Adapter注册:
// 移除原有的ConfigurationCredentialProvider注册 // builder.RegisterType<ConfigurationCredentialProvider>().As<ICredentialProvider>().SingleInstance(); // 注册自定义的托管标识凭证提供器 builder.RegisterType<ManagedIdentityCredentialProvider>() .As<ICredentialProvider>() .SingleInstance(); // 移除原有的BotFrameworkHttpAdapter注册 // builder.RegisterType<BotFrameworkHttpAdapter>().As<IBotFrameworkHttpAdapter>().SingleInstance(); // 注册自定义的Adapter builder.RegisterType<ManagedIdentityBotFrameworkHttpAdapter>() .As<IBotFrameworkHttpAdapter>() .SingleInstance();
注意事项
- 确保Web应用已正确分配用户托管标识,且该标识拥有Bot Channel Registration的相关访问权限。
- 环境变量中仅需保留
MicrosoftAppId、MicrosoftAppTenantId、MicrosoftAppType,无需配置MicrosoftAppPassword。
内容的提问来源于stack exchange,提问作者Aparna
相关产品推荐
相关产品推荐

