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

时间:2019-09-10 14:33:42

标签: typescript botframework azure-bot-service

我正在尝试使用Microsoft botframework和打字稿中的SDK创建聊天机器人。我正在尝试让机器人对用户进行身份验证,然后代表他们与Azure DevOps进行交互。但是,虽然我能够在Azure门户中成功测试身份验证,但是当我尝试对Teams中的用户进行身份验证时,登录“成功”,但是该僵尸程序尝试访问Azure DevOps API时返回了401错误。

我是很多Microsoft堆栈的新手,并且在这里遵循指南:https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-authentication?view=azure-bot-service-4.0&tabs=javascript%2Cbot-oauth

首先,我创建了我的Bot频道注册。它具有与之关联的应用程序注册(已手动创建)。在Azure Portal上的App Service中将appId和secret设置为环境变量。

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

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

当我单击此oauth配置顶部的“测试连接”时,一切正常。我被带到成功页面,并且能够在其中查看令牌。

继续讲代码,我知道团队对于OAuth有点时髦。我的应用程序是使用节点用Typescript编写的,并且需要重新调整以处理服务器方面。我的bot代码扩展了ActivityHandler,具有通常的onMember Leicester,onMessage和onDialog函数。我还添加了onTokenResponseEvent和onUnrecognizedActvityType来处理令牌响应和调用活动类型。

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提示符(连接名称也在App Service的环境变量中):

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错误对象是:

{
    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
    } 
}

这几乎是我问题的详尽描述。如果有人可以帮助我,我将非常感激!我希望我提供了足够的详细信息,但是如果我可以提供更多信息,请告诉我。

2 个答案:

答案 0 :(得分:1)

我对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应该会抛出用户同意屏幕-在您同意之前,还要仔细检查那里的信息。

答案 1 :(得分:0)

我认为这与团队以不同方式处理活动的方式有关。这是来自Node sample的更多信息:

  

在此阶段,此样本的主要重点是如何使用Bot   机器人中对oauth的框架支持。优先排序的原因   这是因为团队的行为与其他渠道中的行为略有不同   对此。具体来说,调用活动会发送到机器人,而不是   而不是其他渠道使用的“事件活动”。此调用活动   如果正在使用OAuthPrompt,则必须转发到对话框。这个   通过将ActivityHandler子类化来完成,此示例包括一个   可重用的TeamsActivityHandler。这个班是未来的候选人   包含在Bot Framework SDK中。

我的建议是快速测试此Node示例,以查看是否可以在Teams中使用它。然后,您应该能够从Node示例中获取该方法,并将其应用于TypeScript(目前 目前还没有TypeScript示例)。