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

基于Python的Microsoft Bot Framework在Teams中偶发Unauthorized错误求助

解决Teams Bot无规律出现Unauthorized错误的问题

问题核心

该错误发生在Bot向Teams回复消息时,reply_to_activity请求返回401未授权,无规律触发,重启容器+删除聊天可临时恢复,本质是Bot与Bot Framework Service/Teams的身份验证链路出现异常。

排查与解决步骤

1. 修复令牌刷新逻辑

Bot Framework Python SDK默认的令牌缓存可能在异步环境(aiohttp)中存在刷新不及时的问题,导致过期令牌被复用。

  • 自定义令牌跟踪与强制刷新:
    继承MicrosoftAppCredentials类,添加令牌生命周期日志,同时在初始化适配器时替换默认凭据,确保令牌过期前主动刷新:
    from botbuilder.core import BotFrameworkAdapter, BotFrameworkAdapterSettings
    from botframework.connector.auth import MicrosoftAppCredentials
    import jwt
    
    class TrackedCredentials(MicrosoftAppCredentials):
        async def get_token(self, force_refresh: bool = False) -> str:
            token = await super().get_token(force_refresh)
            decoded = jwt.decode(token, options={"verify_signature": False})
            print(f"Token acquired, expires at: {decoded['exp']}")
            return token
    
    # 初始化适配器时替换凭据
    adapter_settings = BotFrameworkAdapterSettings(YOUR_APP_ID, YOUR_APP_PASSWORD)
    adapter = BotFrameworkAdapter(adapter_settings)
    adapter.credentials_factory._create_credentials = lambda: TrackedCredentials(YOUR_APP_ID, YOUR_APP_PASSWORD)
    
  • 更新SDK版本:旧版SDK存在令牌刷新bug,执行以下命令升级依赖:
    pip install --upgrade botbuilder-core botframework-connector aiohttp
    

2. 统一会话状态存储

K8S多Pod部署时,本地内存存储会话状态会导致不同Pod的上下文不一致,部分Pod无法获取有效会话令牌。

  • 切换到分布式存储:使用Azure Cosmos DB或Redis存储会话状态,确保所有Pod共享同一上下文:
    from botbuilder.azure import CosmosDbPartitionedStorage
    from botbuilder.core import ConversationState
    
    # Cosmos DB存储配置
    storage = CosmosDbPartitionedStorage(
        cosmos_db_endpoint="YOUR_COSMOS_ENDPOINT",
        auth_key="YOUR_COSMOS_KEY",
        database_id="bot-conversations",
        container_id="conversation-states"
    )
    conversation_state = ConversationState(storage)
    
  • 确保会话状态序列化无丢失,避免身份验证相关字段被遗漏。

3. 检查网络与防火墙配置

防火墙可能拦截Bot向Azure AD/Bot Framework Service的请求,导致令牌无法刷新或请求被拒绝。

  • 开放必要域名:确保Pod能访问以下域名:
    • login.microsoftonline.com(令牌获取)
    • api.botframework.com(Bot服务通信)
  • 代理配置验证:如果使用代理,确保aiohttp正确配置代理,令牌请求可正常通过:
    import aiohttp
    from botframework.connector.aio import ConnectorClient
    
    connector = ConnectorClient(
        YOUR_CREDENTIALS,
        base_url="https://api.botframework.com",
        connector=aiohttp.TCPConnector(proxy="http://your-proxy:port")
    )
    
  • 排查防火墙是否有频率限制,避免令牌刷新请求被误拦截。

4. 添加异常重试机制

遇到401错误时,主动刷新令牌并重试请求,避免直接失败。

  • 包装send_activity方法:
    from botbuilder.schema._models_py3 import ErrorResponseException
    
    async def safe_send(turn_context, activity):
        max_retries = 2
        for attempt in range(max_retries):
            try:
                return await turn_context.send_activity(activity)
            except ErrorResponseException as e:
                if e.response.status == 401 and attempt < max_retries - 1:
                    # 强制刷新令牌
                    await turn_context.adapter.credentials_factory.create_credentials().get_token(force_refresh=True)
                    continue
                raise
    
    在_send_unknown_request_activity中使用safe_send替代原send_activity调用。

5. 处理会话更新事件

删除聊天恢复说明会话级令牌已失效,需在会话更新时重置身份上下文。

  • 重写会话更新处理方法:
    from botbuilder.core import ActivityHandler, TurnContext
    
    class TeamsBot(ActivityHandler):
        async def on_conversation_update_activity(self, turn_context: TurnContext):
            # 会话更新时强制刷新令牌
            await turn_context.adapter.credentials_factory.create_credentials().get_token(force_refresh=True)
            await super().on_conversation_update_activity(turn_context)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:07:56