Bot Framework 身份验证问题 - 获取 401

Bot Framework Authentication Issues - Getting 401

我正在尝试使用 Microsoft botframework 和 typescript 中的 SDK 创建聊天机器人。我正在尝试让机器人对用户进行身份验证,然后代表他们与 Azure DevOps 进行交互。但是,虽然我能够在 Azure 门户中成功测试身份验证,但当我尝试在 Teams 中对用户进行身份验证时,登录 "succeeds",但机器人 returns 出现 401 错误,试图访问 Azure DevOps API的。

我对很多 Microsoft 堆栈都是新手,并且正在按照此处的指南进行操作:https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-authentication?view=azure-bot-service-4.0&tabs=javascript%2Cbot-oauth

首先,我创建了机器人频道注册。它有一个与之关联的应用程序注册(手动创建)。 appId 和 secret 在 Azure 门户上的应用服务中设置为环境变量。

其次,我为我的 Azure Devops 授权创建了另一个应用程序注册。此应用程序注册的重定向 URI 为“https://token.botframework.com/.auth/web/redirect”,并为其创建了一个秘密。此应用程序注册还设置为具有 Azure Devops 的 API 权限 "user_impersonation"。

第三,我进入了我的 Bot Channels Registration,单击 "Settings" blade,并配置了 OAuth 连接设置。此设置的名称为 "azureDevopsOauth",是为 Azure Active Directory V2 服务提供商设置的,包括我在第二步中注册的应用程序的客户端 ID、机密和租户 ID。它还将范围设置为 "openid".

当我单击此 oauth 配置顶部的 "Test Connection" 时,一切正常。我被带到一个成功页面,并且能够在那里查看令牌。

继续看代码,我知道团队对 OAuth 有点陌生。我的应用程序是使用 node 和 restify 以 typescript 编写的,以处理服务器方面的问题。我的机器人代码扩展了 ActivityHandler,具有常用的 onMembersAdded、onMessage 和 onDialog 函数。我还添加了一个 onTokenResponseEvent 和 onUnrecognizedActvityType 来处理令牌响应并调用 activity 类型。

this.onTokenResponseEvent(async (context, next) => {
    console.log('Running dialog with Token Response Event Activity.');

    await this.dialog.run(context, this.dialogState);

    await next();
});

this.onUnrecognizedActivityType(async (context, next) => {
    if (context.activity.type === ActivityTypes.Invoke) {
        await this.dialog.run(context, this.dialogState);
    }
    await next();
});

最后,在我的主对话框中,我创建了一个 oauth 提示(连接名称也在应用服务的环境变量中):

this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
    connectionName: process.env.connectionName,
    text: 'Before we get started, could you please sign in?',
    title: 'Sign In',
    timeout: 300000
}));

此提示已添加到此处的瀑布对话框:

this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
    this.loginStep.bind(this),
    this.confirmStep.bind(this),
    this.projectStep.bind(this),
    this.serviceStep.bind(this),
    this.getServiceDialogStep.bind(this)
]));

这是我的机器人的开始。因此,当您与它交互时,它会立即要求您登录。登录后,我可以看到流程移动到确认步骤,因为我正在那里注销令牌以进行调试。

我正在使用 Azure Devops Node API 来击中 Azure API。我根据令牌响应使用不记名令牌身份验证句柄进行设置:

const authHandler = azdev.getBearerHandler(authToken);
this.connection = new azdev.WebApi(orgUrl, authHandler);

不幸的是,一旦代码移动到项目步骤,它试图获取连接和项目,我就会收到 401 错误。获取连接时会抛出错误,因此它永远不会到达 getProjects 函数:

this.coreApi = await this.connection.getCoreApi();
let projects = await this.coreApi.getProjects();

我不知道我可能设置错了什么,但理想情况下我希望能够使用登录用户凭据访问这些服务。

如果有帮助的话,我得到的实际 401 错误 object 是这样的:

{
    Error: TF400813: The user '' is not authorized to access this resource.
          at RestClient.<anonymous> (/home/site/wwwroot/node_modules/typed-rest-client/RestClient.js:200:31)
          at Generator.next (<anonymous>)
          at fulfilled (/home/site/wwwroot/node_modules/typed-rest-client/RestClient.js:6:58)
          at process._tickCallback (internal/process/next_tick.js:68:7)
    statusCode: 401,
    result: {
        '$id': '1',
        innerException: null,
        message: 'TF400813: The user \'\' is not authorized to access this resource.',
        typeName: 'Microsoft.TeamFoundation.Framework.Server.UnauthorizedRequestException, Microsoft.TeamFoundation.Framework.Server',
        typeKey: 'UnauthorizedRequestException',
        errorCode: 0,
        eventId: 3000
    } 
}

这几乎是对我的问题的详尽描述。如果有人可以提供帮助,我将不胜感激!我希望我已经提供了足够的细节,但如果我还能提供更多,请告诉我。

我认为这与 Teams 处理活动的方式不同有关。这是来自 Node sample:

的更多信息

At this stage the primary focus of this sample is how to use the Bot Framework support for oauth in your bot. The reason for prioritizing this is that Teams behaves slightly differently than other channels in this regard. Specifically an Invoke Activity is sent to the bot rather than the Event Activity used by other channels. This Invoke Activity must be forwarded to the dialog if the OAuthPrompt is being used. This is done by subclassing the ActivityHandler and this sample includes a reusable TeamsActivityHandler. This class is a candidate for future inclusion in the Bot Framework SDK.

我的建议是快速测试此 Node 示例,看看您是否可以在 Teams 中使用它。然后您应该能够采用 Node 示例中的方法并将其应用于 TypeScript(当前 不是 TypeScript 的示例)。

我不太了解 Azure Devops api,但您可能使用了不正确的令牌。

在 OAuth 连接设置中,您将范围设置为 "openid",因此您将获得一个目标为 Graph api 作为受众的令牌,而不是 Azure Devops rest api。 您可以通过将令牌放在 jwt.ms 上来验证它,检查解码的 audscp 声明。应该和Azure Devops无关

OAuth2 令牌仅适用于其预期的资源(受众)。您不能使用图形令牌与 Azure 开发人员对话 api。

请尝试使用正确的 Azure devops 范围更新您的 "azureDevopsOauth" OAuth 连接设置。可用范围似乎已记录 here,例如vso.build 而不是 openid 如果你想阅读构建工件。您可以将多个以逗号分隔的 azure dev ops 范围作为值: vso.build,vso.code,vso.release

并且请选择启用场景所需的最少范围。

执行此操作后,OAuthPrompt 应该会显示用户同意屏幕 - 在您同意之前仔细检查那里的信息。