【问题标题】:Calling Microsoft Graph API from inside Azure Functions从 Azure Functions 内部调用 Microsoft Graph API
【发布时间】:2017-10-08 21:48:34
【问题描述】:

我正在尝试编写一个调用 Microsoft Graph API 的简单 Azure 函数。但我无法使 access_token 工作。这是我所做的:

  1. 从 Azure 门户创建了一个新的 Azure Function App
  2. 开启“App Service Authentication”设置,并指示其使用 AAD 登录(管理模式为 Express)。
  3. 将应用配置为具有委派权限,例如 Microsoft Graph 的“登录并读取用户配置文件”。
  4. 创建了一个新的 JavaScript 函数 HttpTriggerJS1
  5. 将此函数的授权级别更改为“匿名”(否则默认情况下“函数”级别甚至不允许我运行该函数,总是返回 401 Unauthorized)
  6. 安装了必要的 Node 模块 (npm install request)
  7. 以及实际功能:

    var request = require('request');
    module.exports = function (context, req) {
        var token = req.headers['x-ms-token-aad-access-token'];
        var reqUrl = 'https://graph.microsoft.com/v1.0/me/';
        request.get(reqUrl, {'auth': {'bearer': token}}, function (err, response, msg) {
            context.res = {
                body: msg
            };
            context.done();
        });
    };
    
  8. 在单独的浏览器窗口中测试了此功能。让我正确登录到 AAD。

  9. 但是 Graph 返回的消息是:

    "{
      "error": {
        "code": "InvalidAuthenticationToken",
        "message": "CompactToken parsing failed with error code: -2147184105",
        "innerError": {
          "request-id": "4c78551d-f0fe-4104-b1d3-e2d96fd3c02c",
          "date": "2017-05-16T19:11:14"
        }
      }
    }"
    

我查看了从req.headers['x-ms-token-aad-access-token'] 获得的令牌。它有点像“AQABAA....”,这似乎与我之前看到的以“eyJ....”开头的常规 access_token 不同。

这里可能有什么问题?调用 Graph API 时,我应该使用请求标头中的 access_token 吗?

谢谢!

编辑:

根据 Chris Gillum 的建议,我还研究了“代表”流程。这是我更新的函数,它通过提供 id_token(从请求标头中检索)来获取特定资源的 access_token(在我的情况下为 https://graph.microsoft.com)。:

var request = require('request');

module.exports = function (context, req) {
    var parameters = {
        grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        client_id: process.env.WEBSITE_AUTH_CLIENT_ID,
        client_secret: process.env.WEBSITE_AUTH_CLIENT_SECRET,
        assertion: req.headers['x-ms-token-aad-id-token'],
        resource: 'https://graph.microsoft.com',
        requested_token_use: 'on_behalf_of'
    };
    request.post('https://login.microsoftonline.com/microsoft.com/oauth2/token', {form: parameters}, function (aadErr, aadResponse, aadMsg) {
        var msgJson = JSON.parse(aadMsg);
        request.get('https://graph.microsoft.com/v1.0/me/', {'auth': {'bearer': msgJson.access_token}}, function (err, response, msg) {
            context.res = {
                body: msg
            };
            context.done();
        });
    });
};

【问题讨论】:

  • 我认为问题在于您使用的令牌没有与之关联的任何资源。我通常可以说,因为令牌不是你注意到的 JWT。我将添加一个答案,其中包含一些您必须获得正确令牌形状的选项。

标签: javascript node.js azure microsoft-graph-api azure-functions


【解决方案1】:

在使用 Azure 应用服务身份验证/授权时,您可以通过两种方式完成这项工作:

  1. 在函数应用的 AAD 配置中分配默认资源。
  2. 使用 AAD on-behalf-of flow 将您的 ID 令牌 (x-ms-token-aad-id-token) 交换为 MS Graph 访问令牌。

不需要任何代码更改的最简单方法是执行 #1。我在 App Service Auth and the Azure AD Graph API 博客文章中概述了该过程(需要一些更新),但我会在此处为您提供 Microsoft Graph 的函数优化版本。

你需要做的主要事情是:

  1. 确保您的 AAD 设置包含客户端密码(您已经拥有该密码)。
  2. 确保您的 AAD 设置有权访问 Microsoft Graph(您已经这样做了)。
  3. Resource Explorer 中打开您的函数应用(使用平台设置下的门户中的链接),导航到左侧面板上的config/authsettings,更改"additionalLoginParams"null["resource=https://graph.microsoft.com"],然后保存更改。

执行此操作并再次登录后,x-ms-token-aad-access-token 请求标头将始终为您提供与 Microsoft Graph 一起使用的访问令牌。

上述方法的缺点是,如果您需要从函数应用访问多个受 AAD 保护的资源,它对您没有帮助。如果这对您来说是个问题,那么您需要使用上面的方法 #2。

【讨论】:

  • 太棒了!奇迹般有效。非常感谢! :)
  • 我不确定#1 是否适用于 MSA 帐户(@live.com、@outlook.com 等)。如果您在使用 MSA 帐户时遇到问题,请尝试 #2。
  • 不确定#2 是否适用于 MSA.... 我尝试过但失败了。也许一篇关于如何以任何方式实现这一目标的博客文章?目前这似乎是不可能的。
  • 选项 1 对我有用。优秀的解决方案!拯救了我的一天。非常感谢!
  • 选项 1 有效,但有时我会收到“访问令牌已过期”。来自 GraphAPI。为什么?
【解决方案2】:

Azure Functions 现在支持 Microsoft Graph 的本机身份验证。文档位于https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-microsoft-graph

https://azure.microsoft.com/en-us/resources/videos/azure-friday-navigating-the-microsoft-graph-with-azure-functions-henderson/还有一个视频

例如,您可以创建一个 HttpTrigger 函数并将以下内容添加到 function.json。

{
   "type": "token",
   "direction": "in",
   "name": "graphToken",
   "resource": "https://graph.microsoft.com",
   "identity": "userFromRequest"
}

然后,您可以代表发出请求的用户查询 Graph API。访问令牌作为参数传入,您可以将其作为标头添加到 HttpClient

using System.Net; 
using System.Net.Http; 
using System.Net.Http.Headers; 

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, string graphToken, TraceWriter log)
{
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
    return await client.GetAsync("https://graph.microsoft.com/v1.0/me/");
}

您还可以使用 ClientCredentials 身份验证模式运行函数,这意味着它作为应用运行,而不是在特定用户的上下文中运行。

【讨论】:

    【解决方案3】:

    标头应包含正确的访问令牌(此处有更多详细信息): https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-authentication

    这是另一个遇到相同错误的帖子,可能会有所帮助: How do I create an auth token with the new microsoft graph api?

    一种可能的解决方法是使用服务主体身份验证流程,让函数应用能够通过 AAD 调用 Graph API。

    https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-overview#service-to-service-authentication

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-20
      • 1970-01-01
      • 1970-01-01
      • 2020-07-03
      • 2017-07-01
      • 2018-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多