You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Microsoft Bot Framework机器人至特定AD租户?求其他方案及最佳实践

针对MS Teams Bot的租户/用户访问限制方案

首先,针对你的场景,我们可以从配置层面和代码层面两个方向来解决,优先推荐配置层面的方案(更简洁安全),如果必须保留多租户特性再用代码层的最佳实践:

一、配置层面的限制方案(无需代码改动)

1. 修改Azure AD应用注册的租户范围

如果你的Bot仅需服务于特定租户(不需要支持Web渠道的全球用户),直接把应用注册从“多租户”改成“单租户”:

  • 登录Azure门户,找到你的Bot对应的AD应用注册
  • 进入“概述”页面,点击“管理谁可以访问此应用”
  • 选择“仅限此组织目录中的账户”,保存更改

这样只有你租户内的用户能访问Bot,全球其他租户的用户无法授权使用。如果还需要排除租户内的来宾用户,再结合代码层面的检查即可。

2. Teams应用清单补充限制

如果你是通过Teams App Studio发布Bot,可以在应用清单(manifest.json)中强化租户绑定:

  • 在manifest.json的requiredResourceAccess节点中,指定仅允许你的租户ID对应的资源权限
  • 也可以设置validDomains为你的租户域名,进一步限制应用的访问范围

二、代码层面的最佳实践(保留多租户但限制访问)

如果必须保留多租户特性(比如同时支持Web和Teams渠道),可以用以下无副作用的代码安全措施:

1. 全局租户ID检查(最常用,无需Graph调用)

Bot收到的每个Activity里都包含租户ID(Activity.Conversation.TenantId),你可以预先定义允许的租户ID列表,在Bot入口或中间件中做校验:

protected override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
    // 定义允许的租户ID集合
    var allowedTenantIds = new HashSet<string> { "你的租户ID1", "你的租户ID2" };
    
    if (turnContext.Conversation.TenantId != null && !allowedTenantIds.Contains(turnContext.Conversation.TenantId))
    {
        await turnContext.SendActivityAsync(MessageFactory.Text("抱歉,此Bot仅对特定租户的用户开放。"), cancellationToken);
        return;
    }

    // 继续处理正常业务逻辑
    await base.OnTurnAsync(turnContext, cancellationToken);
}

2. 区分内部用户与来宾用户(排除来宾)

如果需要进一步限制仅允许租户内的内部用户(排除来宾),可以结合Microsoft Graph检查用户类型:

  • 先确保Bot的AD应用注册已获取User.ReadBasic.All权限并获得管理员同意
  • 调用Graph API获取用户的userType属性:
// 注入GraphServiceClient后调用
private async Task<bool> IsInternalUserAsync(string userId, GraphServiceClient graphClient)
{
    var user = await graphClient.Users[userId]
        .Request()
        .Select(u => new { u.UserType })
        .GetAsync();
    return user.UserType == "Member"; // Member为内部用户,Guest为来宾
}

在Bot逻辑中调用该方法,拒绝来宾用户的请求即可。

3. 用中间件做全局拦截

把检查逻辑封装成中间件,所有进入Bot的请求都会先经过校验,无需在每个Dialog中重复代码:

public class TenantValidationMiddleware : IMiddleware
{
    private readonly HashSet<string> _allowedTenantIds;

    public TenantValidationMiddleware(IEnumerable<string> allowedTenantIds)
    {
        _allowedTenantIds = new HashSet<string>(allowedTenantIds);
    }

    public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default)
    {
        if (turnContext.Conversation.TenantId != null && !_allowedTenantIds.Contains(turnContext.Conversation.TenantId))
        {
            await turnContext.SendActivityAsync(MessageFactory.Text("你无权访问此Bot。"), cancellationToken);
            return;
        }

        // 继续执行后续中间件与Bot逻辑
        await next(cancellationToken);
    }
}

// 在Startup.cs中注册中间件
services.AddBot<YourBot>(options =>
{
    // 其他Bot配置...
    options.Middleware.Add(new TenantValidationMiddleware(new[] { "你的租户ID" }));
});

三、最佳实践总结

  1. 优先配置层面:如果不需要多租户,直接改成单租户应用注册,这是最安全且无代码成本的方案
  2. 代码防御分层:用中间件做全局检查,同时在关键Dialog中补充验证,防止绕过
  3. 减少Graph调用:如果需要检查用户类型,缓存用户的userType信息(比如用MemoryCache),避免重复调用Graph
  4. 友好提示:拒绝访问时返回清晰的错误信息,不要静默失败,提升用户体验

内容的提问来源于stack exchange,提问作者kolbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:52:42