无AAD权限时如何为Microsoft Teams聊天机器人实现用户认证?
我正在使用MS Bot Framework SDK 4开发一款机器人,我的Bot API暴露了一个唯一的POST api/messages端点,代码如下:
[Route("api/messages")] [ApiController] public class BotController : ControllerBase { private readonly IBotFrameworkHttpAdapter _adapter; private readonly IBot _bot; public BotController(IBotFrameworkHttpAdapter adapter, IBot bot) { _adapter = adapter; _bot = bot; } [HttpPost, HttpGet] public async Task PostAsync() { // Delegate the processing of the HTTP POST to the adapter. // The adapter will invoke the bot. await _adapter.ProcessAsync(Request, Response, _bot); } }
可以看到,该端点暴露在公网中,没有任何认证机制验证用户是否有权访问api/messages。
查阅Bot Framework文档时看到:
当你通过Azure Bot资源在Azure中注册机器人时,Azure会创建一个Azure Active Directory(Azure AD)注册应用。该应用包含应用ID(MicrosoftAppId)和客户端密钥(MicrosoftAppPassword)。
但由于安全政策限制,我无法使用在Azure门户创建Bot Service时生成的AAD(Azure Active Directory)。
我查阅了多篇关于为机器人实现认证的文档,但根据我的理解,其中大部分都需要访问AAD才能实现:
- 使用SSO认证构建机器人
- 为Bot SDK v4添加认证
- 为应用和消息扩展应用启用SSO
- 为机器人中的自适应卡片通用操作启用SSO
- 使用第三方OAuth提供商启用认证
请问是否有无需使用AAD即可为POST api/messages添加认证的方法?是否有可遵循的操作指南或文档参考?
当然有无需依赖AAD的认证方式来保护api/messages端点,以下是几种直接可落地的方案:
1. API密钥认证
这是最简单的方式,通过自定义请求头携带密钥完成验证:
- 修改
BotController的PostAsync方法,添加密钥校验逻辑:
private readonly IConfiguration _configuration; public BotController(IBotFrameworkHttpAdapter adapter, IBot bot, IConfiguration configuration) { _adapter = adapter; _bot = bot; _configuration = configuration; } [HttpPost, HttpGet] public async Task PostAsync() { // 从请求头获取API密钥并验证 if (!Request.Headers.TryGetValue("X-API-Key", out var apiKey) || apiKey != _configuration["BotApiKey"]) { Response.StatusCode = StatusCodes.Status401Unauthorized; return; } await _adapter.ProcessAsync(Request, Response, _bot); }
- 在
appsettings.json中存储密钥(避免硬编码):
{ "BotApiKey": "your-secure-random-api-key-here" }
- 要求调用方在请求时携带
X-API-Key头,值与配置中的密钥一致。
2. 自定义JWT认证
如果需要更灵活的身份校验,可以实现独立的JWT验证逻辑:
- 在
Program.cs中配置JWT验证服务:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "your-custom-issuer", ValidAudience = "your-custom-audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSecretKey"])) }; }); // 启用认证中间件 builder.Services.AddAuthorization();
- 在
BotController或PostAsync方法上添加[Authorize]属性:
[Authorize] [HttpPost, HttpGet] public async Task PostAsync() { await _adapter.ProcessAsync(Request, Response, _bot); }
- 调用方需使用指定密钥生成符合要求的JWT令牌,在请求头中携带
Authorization: Bearer <token>。
3. IP白名单限制
如果机器人仅对特定IP开放,可以通过IP白名单拦截非法请求:
- 在
BotController中添加IP校验逻辑:
private readonly IConfiguration _configuration; public BotController(IBotFrameworkHttpAdapter adapter, IBot bot, IConfiguration configuration) { _adapter = adapter; _bot = bot; _configuration = configuration; } [HttpPost, HttpGet] public async Task PostAsync() { var allowedIps = _configuration.GetSection("AllowedIPs").Get<string[]>(); var clientIp = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); // 处理IPv6映射的IPv4地址 if (clientIp?.StartsWith("::ffff:") == true) { clientIp = clientIp.Substring(7); } if (!allowedIps.Contains(clientIp)) { Response.StatusCode = StatusCodes.Status403Forbidden; return; } await _adapter.ProcessAsync(Request, Response, _bot); }
- 在
appsettings.json中配置允许的IP列表:
{ "AllowedIPs": ["192.168.1.1", "10.0.0.5"] }
注:如果请求经过反向代理,需额外配置以获取客户端真实IP。
4. 第三方OAuth2提供商集成
可以选择Google、GitHub等非AAD的OAuth2提供商,让调用方先获取第三方令牌,再在控制器中验证令牌有效性。这种方式适合需要对用户身份做精细化校验的场景,核心遵循OAuth2标准流程实现即可。
内容的提问来源于stack exchange,提问作者diegobarriosdev

