Командный бот выдает несанкционированную ошибку при попытке отправить сообщение обратно - PullRequest
3 голосов
/ 03 марта 2020

Я пытаюсь создать простого бота MS Teams, используя Python каркас бота SDK. При локальном тестировании моего бота с помощью эмулятора все работает нормально. Я зарегистрировал бота, используя устаревший портал здесь https://dev.botframework.com/bots, поскольку я не хочу создавать подписку Azure.

Я добавил идентификатор приложения и секрет приложения в бот и развернул его на компьютере EC2 с использованием API-шлюза (с интеграцией прокси-сервера HTTP) для получения URL-адреса HTTPS для конечной точки обмена сообщениями.

При развертывании код может получать и анализировать сообщения от обеих функций тестирования на устройстве dev фреймворк и из действующего развернутого приложения в командах. Тем не менее, при попытке ответить на сообщение, я получаю сообщение Несанкционированная ошибка.

Вот трассировка стека:

[on_turn_error] unhandled error: Operation returned an invalid status code 'Unauthorized'
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/bot_adapter.py", line 103, in run_pipeline
    context, callback
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/middleware_set.py", line 69, in receive_activity_with_status
    return await self.receive_activity_internal(context, callback)
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/middleware_set.py", line 79, in receive_activity_internal
    return await callback(context)
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/activity_handler.py", line 28, in on_turn
    await self.on_message_activity(turn_context)
  File "/home/ec2-user/bot/bot.py", line 24, in on_message_activity
    return await turn_context.send_activity(response)
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/turn_context.py", line 165, in send_activity
    result = await self.send_activities([activity_or_text])
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/turn_context.py", line 198, in send_activities
    return await self._emit(self._on_send_activities, output, logic())
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/turn_context.py", line 276, in _emit
    return await logic
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/turn_context.py", line 193, in logic
    responses = await self.adapter.send_activities(self, output)
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/bot_framework_adapter.py", line 444, in send_activities
    raise error
  File "/usr/local/lib/python3.7/site-packages/botbuilder/core/bot_framework_adapter.py", line 431, in send_activities
    activity.conversation.id, activity.reply_to_id, activity
  File "/usr/local/lib/python3.7/site-packages/botframework/connector/aio/operations_async/_conversations_operations_async.py", line 533, in reply_to_activity
    raise models.ErrorResponseException(self._deserialize, response)
botbuilder.schema._models_py3.ErrorResponseException: Operation returned an invalid status code 'Unauthorized'

Мой код приложения:

CONFIG = DefaultConfig()
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD,
                                       CONFIG.APP_AUTH_TENANT, CONFIG.APP_OAUTH_ENDPOINT)
ADAPTER = BotFrameworkAdapter(SETTINGS)


# Catch-all for errors.
async def on_error(context: TurnContext, error: Exception):
    print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
    traceback.print_exc()

    # Send a message to the user
    await context.send_activity("The bot encountered an error or bug.")
    await context.send_activity("To continue to run this bot, please fix the bot source code.")
    # Send a trace activity if we're talking to the Bot Framework Emulator
    if context.activity.channel_id == "emulator":
        # Create a trace activity that contains the error object
        trace_activity = Activity(
            label="TurnError",
            name="on_turn_error Trace",
            timestamp=datetime.utcnow(),
            type=ActivityTypes.trace,
            value=f"{error}",
            value_type="https://www.botframework.com/schemas/error",
        )
        # Send a trace activity, which will be displayed in Bot Framework Emulator
        await context.send_activity(trace_activity)


ADAPTER.on_turn_error = on_error
APP_ID = SETTINGS.app_id
dynamodb = boto3.resource("dynamodb")
CONVERSATION_REFERENCES = dynamodb.Table("ConversationReferences")

# Create the Bot
BOT = MyBot(CONVERSATION_REFERENCES)


# Listen for incoming requests on /api/messages
async def messages(req):
    print(f"Message Received - {str(datetime.now())}")
    json_request = await req.json()
    print(f"Request Body: {json_request}")
    activity = Activity().deserialize(json_request)
    print("Request successfully deserialized")
    auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
    try:
        print("Sending activity to adapter")
        response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
        if response:
            return Response(status=response.status, text=response.body)
        return Response(status=201)
    except Exception as exception:
        raise exception

async def health(req):
    return Response(status=200, text="Working")

APP = web.Application(middlewares=[aiohttp_error_middleware])
APP.router.add_post("/api/messages", messages)
APP.router.add_get("/health", health)

if __name__ == "__main__":
    web.run_app(APP)

А мой бот-код:

class MyBot(ActivityHandler):

    def __init__(self, conversation_references):
        self.conversation_references = conversation_references

    async def on_message_activity(self, turn_context: TurnContext):
        print("Message received by bot adapter")
        # The next two lines also cause an unauthorized error. I commented them out to try and simplify
        # team_details = await teams.TeamsInfo.get_members(turn_context)
        # user = team_details[1].email
        user = "test@test.com"
        conversation = self.conversation_references.get_item(Key={"user": user})
        if "Item" in conversation:
            response = "You are already registered"
        else:
            conversation = TurnContext.get_conversation_reference(turn_context.activity)
            item = {"user": user, "conversation": conversation.as_dict()}
            self.conversation_references.put_item(Item=item)
            response = "You have been successfully registered!"
        return await turn_context.send_activity(response)

Обновление: при локальном тестировании я не добавил идентификатор приложения и пароль в эмулятор. Когда я это делаю, в режиме отладки я получаю следующее сообщение об ошибке: «Произошла ошибка во время POSTing» / команда «INSPECT open» для диалога xxxxxx | livechat: 400: неверный идентификатор приложения или пароль приложения Microsoft для бота. "

Я на 100% уверен, что идентификатор и пароль верны, поскольку я вручную использовал конечную точку токена со страницы регистрации, чтобы получить токен доступа с этими учетными данными. Это может быть связано с тем, что в коде и использовании конечной точки вручную я могу указать идентификатор каталога (арендатора), в то время как я не могу сделать это с помощью эмулятора.

Еще один странный момент заключается в том, что когда эмулятор возвращает этот ответ на самом деле, кажется, не отправляет запрос в мою локальную конечную точку, поэтому я не уверен, откуда приходит ответ 400.

Ответы [ 2 ]

2 голосов
/ 07 марта 2020

Вам необходимо убедиться, что вы используете учетные данные мультитенантного приложения AAD, как описано здесь .

0 голосов
/ 06 марта 2020

Ниже представлен контент, который вы получите от команд. У него есть ключ serviceURL, который будет использоваться для подключения к вашему боту, который развернут в ваших командах с использованием других параметров, доступных в ниже json, который я заменил логическими именами между << и >>.

    { text: 'help',
  textFormat: 'plain',
  type: 'message',
  timestamp: 2020-03-05T12:29:26.830Z,
  localTimestamp: 2020-03-05T12:29:26.830Z,
  id: '1583411366810',
  channelId: 'msteams',
  serviceUrl: 'https://smba.trafficmanager.net/emea/',
  from:
   { id:
      '<<Use ID>>',
     name: '<<Display Name>>',
     aadObjectId: '<<objectID>>' },
  conversation:
   { conversationType: 'personal',
     tenantId: '<<Microsoft Tenant ID>>',
     id:
      '<<Unique Conversation ID>>' },
  recipient:
   { id: '<<BotID>>', name: 'Sybot' },
  entities:
   [ { locale: 'en-US',
       country: 'US',
       platform: 'Windows',
       type: 'clientInfo' } ],
  channelData: { tenant: { id: '<<Microsoft Tenant ID>>' } },
  locale: 'en-US' }

Получив его, вы должны использовать приведенный ниже код, чтобы сделать URL-адрес службы доверенным, чтобы при отправке сообщения обратно пользователю не возникала неавторизованная ошибка.

const { MicrosoftAppCredentials } = require('botbuilder/node_modules/botframework-connector'); 
const { BotFrameworkAdapter } = require('botbuilder');
const { TurnContext } = require('botbuilder');

    const adapter = new BotFrameworkAdapter({
        appId: <<Your App ID>>,
        appPassword: <<Your App Password>>,
    });
    turnContext = new TurnContext(adapter, contextActivity);

    if (!MicrosoftAppCredentials.isTrustedServiceUrl(serviceUrl)) {
        MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
    }
   await context.sendActivity(`Hello World`);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...