单租户团队机器人身份验证错误:缺少 access_token

问题描述 投票:0回答:1

我正在使用 Python 中的

FastAPI
botbuilder-core
库开发 Teams 机器人。我想限制该机器人仅在我的公司内使用,并出于保密原因将其保留为单个租户应用程序。但是,我遇到了一个问题,即机器人尝试发送消息但失败并出现与
access_token
相关的错误。

以下是相关代码片段:

CONFIG = DefaultConfig()

# BotFramework Adapter setup
ADAPTER = CloudAdapter(ConfigurationBotFrameworkAuthentication(CONFIG))

# Teams Bot
BOT = TeamsBot()

@app.post("/api/messages")
@app.options("/api/messages")
async def messages(req: Request) -> Response:
    # Main bot message handler.
    if "application/json" in req.headers["Content-Type"]:
        body = await req.json()
    else:
        return Response(status_code=HTTPStatus.UNSUPPORTED_MEDIA_TYPE)

    activity = Activity().deserialize(body)
    if not isinstance(activity, Activity):
        print(f"Error: Expected Activity, got {type(activity)} instead.")
        return Response(status_code=400)
    auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""

    response = await ADAPTER.process_activity(auth_header, activity, BOT.on_turn)
    if response:
        return json_response(data=response.body, status=response.status)
    return Response(status_code=201)

追溯:

Traceback (most recent call last):
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 408, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\fastapi\applications.py", line 292, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
    raise exc
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\middleware\sessions.py", line 86, in __call__
    await self.app(scope, receive, send_wrapper)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\middleware\exceptions.py", line 79, in __call__
    raise exc
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 20, in __call__
    raise e
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\starlette\routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\fastapi\routing.py", line 273, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\fastapi\routing.py", line 190, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject\_api\fast_api.py", line 113, in messages
    return Response(status_code=201)
               ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\cloud_adapter_base.py", line 364, in process_activity
    await self.run_pipeline(context, logic)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\bot_adapter.py", line 181, in run_pipeline
    raise error
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\bot_adapter.py", line 174, in run_pipeline
    return await self._middleware.receive_activity_with_status(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\middleware_set.py", line 69, in receive_activity_with_status
    return await self.receive_activity_internal(context, callback)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\middleware_set.py", line 79, in receive_activity_internal
    return await callback(context)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject\services\ProjectName\teams_bot\bot.py", line 69, in on_turn
    await super().on_turn(turn_context)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\activity_handler.py", line 70, in on_turn
    await self.on_message_activity(turn_context)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject\services\ProjectName\teams_bot\bot.py", line 27, in on_message_activity
    await self.get_template_quote(turn_context)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject\services\ProjectName\teams_bot\bot.py", line 223, in get_template_quote
    await self._send_file_card(turn_context, filename, file_size)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject\services\ProjectName\teams_bot\bot.py", line 250, in _send_file_card
    await turn_context.send_activity(reply_activity)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\turn_context.py", line 173, in send_activity
    result = await self.send_activities([activity_or_text])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\turn_context.py", line 225, in send_activities
    return await self._emit(self._on_send_activities, output, logic())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\turn_context.py", line 303, in _emit
    return await logic
           ^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\turn_context.py", line 220, in logic
    responses = await self.adapter.send_activities(self, output)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botbuilder\core\cloud_adapter_base.py", line 93, in send_activities
    response = await connector_client.conversations.reply_to_activity(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botframework\connector\aio\operations_async\_conversations_operations_async.py", line 523, in reply_to_activity
    response = await self._client.async_send(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\msrest\async_client.py", line 115, in async_send
    pipeline_response = await self.config.pipeline.run(request, **kwargs)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\msrest\pipeline\async_abc.py", line 159, in run
    return await first_node.send(pipeline_request, **kwargs)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\msrest\pipeline\async_abc.py", line 79, in send
    response = await self.next.send(request, **kwargs)  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\msrest\pipeline\async_requests.py", line 99, in send
    self._creds.signed_session(session)
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botframework\connector\auth\app_credentials.py", line 98, in signed_session
    auth_token = self.get_access_token()
                 ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X(Aspe\PycharmProjects\TeamsBotProject_Main\venv\Lib\site-packages\botframework\connector\auth\microsoft_app_credentials.py", line 65, in get_access_token
    return auth_token["access_token"]
           ~~~~~~~~~~^^^^^^^^^^^^^^^^
KeyError: 'access_token'

错误:

{'error': 'unauthorized_client', 'error_description': "AADSTS700016: Application with identifier 'AppID' was not found in the directory 'Bot Framework'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant. Trace ID: 00 Correlation ID: 00 Timestamp: 2024-03-25 20:35:48Z", 'error_codes': [700016], 'timestamp': '2024-03-25 20:35:48Z', 'trace_id': '00', 'correlation_id': '00', 'error_uri': 'https://login.microsoftonline.com/error?code=700016'}

在上面的代码中,我仅将应用程序 ID 和应用程序密钥传递给 ConfigurationBotFrameworkAuthentication 实例。我注意到当我切换到多租户模式时不会发生错误,但我想将机器人保留为单租户应用程序。

我有一种感觉,我可能需要传递额外的信息才能进行正确的验证或更改 Azure 中的某些设置。 在我的项目中,在“身份验证”选项卡下,我选择了“单租户”,

但在机器人的“Configuration”选项卡中,它显示“MultiTenant”。我不确定这种差异是否导致了问题。

我使用

FastAPI
运行机器人,/api/messages 端点负责处理 Teams 消息。我的目标是允许我公司内的用户自由地将这个机器人添加到他们的集合中并使用它。

我观察到,当我发送消息时,它不会给我有关 access_token 的错误,但它显示机器人正在尝试发送消息并失败。

我希望获得有关如何使用

FastAPI
botbuilder-core
库正确配置单租户 Teams 机器人身份验证的指导。我是否需要传递其他信息或修改 Azure 中的任何设置才能解决此问题?

python azure botframework microsoft-teams microsoft-graph-teams
1个回答
0
投票

正如上面的评论所述,虽然它不直观,但您需要为应用程序启用多租户才能使机器人正常工作。然而,来自用户的实际消息在有效负载中包含租户 ID,因此可以对其进行过滤并阻止其他任何内容。实现此目的的一种方法是使用中间件,其中有一个示例(恐怕不是 C#,但希望它可以为您提供正确的起点):https://github.com/OfficeDev/ BotBuilder-MicrosoftTeams-dotnet/blob/master/CSharp/Microsoft.Bot.Builder.Teams/Middlewares/TeamsTenantFilteringMiddleware.cs 或者您可以在处理程序中执行此操作,甚至可以在机器人本身的 OnTurn 或 OnMessage 事件处理程序中执行此操作。

这肯定提供了一定程度的保护,因为只有 Bot Framework 服务拥有您的机器人的端点地址 - 它永远不会发布给最终客户端 - 因此,如果有任何内容到达您的机器人,您可以在中间件或处理程序或类似的中进行过滤。但是,如果您想要更高级别的安全性,这样,如果恶意行为者以某种方式发现并调用您的机器人的 Web 端点,它也会被阻止,那么您可以考虑实施 SSO,在这种情况下,您可以确保您拥有 (a)有效的令牌,并且 (b) 100% 来自正确的租户。您可以在这里阅读更多相关信息:https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-overview

© www.soinside.com 2019 - 2024. All rights reserved.