从 Azure Functions 内部调用 Microsoft Graph API
Calling Microsoft Graph API from inside Azure Functions
我正在尝试编写一个调用 Microsoft Graph API 的简单 Azure 函数。但是我无法使 access_token 工作。这是我所做的:
- 从 Azure 门户创建了一个新的 Azure Function App
- 打开 "App Service Authentication" 设置并指示其使用 AAD 登录(管理模式为 Express)。
- 已将应用配置为具有 Microsoft Graph 的委派权限,例如 "Sign in and read user profile"。
- 创建了一个新的 JavaScript 函数 HttpTriggerJS1
- 将此函数的授权级别更改为 "Anonymous"(否则默认 "Function" 级别甚至不允许我 运行 该函数,总是返回 401 Unauthorized)
- 安装了必要的节点模块(
npm install request
)
而实际函数:
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();
});
};
在单独的浏览器中测试了此功能 window。让我正确登录到 AAD。
但是从 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好像不一样
这里可能有什么问题?调用图形 API 时,我是否应该使用请求 headers 中的 access_token?
谢谢!
编辑:
根据 Chris Gillum 的建议,我也研究了 "on-behalf-of" 流程。这是我更新的函数,它通过提供 id_token(从请求 headers 中检索)获取特定资源的 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();
});
});
};
header 应该包含正确的 access-token(此处有更多详细信息):
https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-authentication
这是另一个遇到同样错误的 post,可能会有帮助:
How do I create an auth token with the new microsoft graph api?
一种可能的解决方法是使用服务主体身份验证流程,您可以在其中启用函数应用程序以通过 AAD 调用 Graph API。
使用 Azure 应用服务身份验证/授权时,您可以通过两种方式完成这项工作:
- 在函数应用的 AAD 配置中分配默认资源。
- 使用 AAD on-behalf-of flow 将您的 ID 令牌 (
x-ms-token-aad-id-token
) 换成 MS Graph 访问令牌。
不需要任何代码更改的最简单方法是执行#1。我在我的 App Service Auth and the Azure AD Graph API 博客 post 中概述了该过程(需要一些更新),但我将在此处为您提供 Microsoft Graph 的 Functions-optimized 版本。
您需要做的主要事情是:
- 确保您的 AAD 设置包括 client-secret(您已经有了)。
- 确保您的 AAD 设置具有访问 Microsoft Graph 的权限(您已经这样做了)。
- 在 Resource Explorer 中打开您的函数应用(使用门户中 平台设置 下的 link),导航至 config/authsettings 在 left-hand 面板上,将
"additionalLoginParams"
从 null
更改为 ["resource=https://graph.microsoft.com"]
,然后保存更改。
执行此操作并再次登录后,x-ms-token-aad-access-token
请求 header 将始终为您提供适用于 Microsoft Graph 的访问令牌。
上述方法的缺点是,如果您需要从您的函数应用程序访问多个 AAD-protected 资源,它对您没有帮助。如果这对您来说是个问题,那么您需要使用上面的方法 #2。
Azure Functions 现在支持 Microsoft Graph 的本机身份验证。文档位于 https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-microsoft-graph
上还有一个视频
例如,您可以创建一个 HttpTrigger 函数并将以下内容添加到 function.json。
{
"type": "token",
"direction": "in",
"name": "graphToken",
"resource": "https://graph.microsoft.com",
"identity": "userFromRequest"
}
然后,您可以代表发出请求的用户查询图表 API。访问令牌作为参数传入,您可以将其作为 header 添加到 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 身份验证模式运行,这意味着它 运行 作为应用程序而不是在特定用户的上下文中。
我正在尝试编写一个调用 Microsoft Graph API 的简单 Azure 函数。但是我无法使 access_token 工作。这是我所做的:
- 从 Azure 门户创建了一个新的 Azure Function App
- 打开 "App Service Authentication" 设置并指示其使用 AAD 登录(管理模式为 Express)。
- 已将应用配置为具有 Microsoft Graph 的委派权限,例如 "Sign in and read user profile"。
- 创建了一个新的 JavaScript 函数 HttpTriggerJS1
- 将此函数的授权级别更改为 "Anonymous"(否则默认 "Function" 级别甚至不允许我 运行 该函数,总是返回 401 Unauthorized)
- 安装了必要的节点模块(
npm install request
) 而实际函数:
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(); }); };
在单独的浏览器中测试了此功能 window。让我正确登录到 AAD。
但是从 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....".
这里可能有什么问题?调用图形 API 时,我是否应该使用请求 headers 中的 access_token?
谢谢!
编辑:
根据 Chris Gillum 的建议,我也研究了 "on-behalf-of" 流程。这是我更新的函数,它通过提供 id_token(从请求 headers 中检索)获取特定资源的 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();
});
});
};
header 应该包含正确的 access-token(此处有更多详细信息): https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-authentication
这是另一个遇到同样错误的 post,可能会有帮助: How do I create an auth token with the new microsoft graph api?
一种可能的解决方法是使用服务主体身份验证流程,您可以在其中启用函数应用程序以通过 AAD 调用 Graph API。
使用 Azure 应用服务身份验证/授权时,您可以通过两种方式完成这项工作:
- 在函数应用的 AAD 配置中分配默认资源。
- 使用 AAD on-behalf-of flow 将您的 ID 令牌 (
x-ms-token-aad-id-token
) 换成 MS Graph 访问令牌。
不需要任何代码更改的最简单方法是执行#1。我在我的 App Service Auth and the Azure AD Graph API 博客 post 中概述了该过程(需要一些更新),但我将在此处为您提供 Microsoft Graph 的 Functions-optimized 版本。
您需要做的主要事情是:
- 确保您的 AAD 设置包括 client-secret(您已经有了)。
- 确保您的 AAD 设置具有访问 Microsoft Graph 的权限(您已经这样做了)。
- 在 Resource Explorer 中打开您的函数应用(使用门户中 平台设置 下的 link),导航至 config/authsettings 在 left-hand 面板上,将
"additionalLoginParams"
从null
更改为["resource=https://graph.microsoft.com"]
,然后保存更改。
执行此操作并再次登录后,x-ms-token-aad-access-token
请求 header 将始终为您提供适用于 Microsoft Graph 的访问令牌。
上述方法的缺点是,如果您需要从您的函数应用程序访问多个 AAD-protected 资源,它对您没有帮助。如果这对您来说是个问题,那么您需要使用上面的方法 #2。
Azure Functions 现在支持 Microsoft Graph 的本机身份验证。文档位于 https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-microsoft-graph
上还有一个视频例如,您可以创建一个 HttpTrigger 函数并将以下内容添加到 function.json。
{
"type": "token",
"direction": "in",
"name": "graphToken",
"resource": "https://graph.microsoft.com",
"identity": "userFromRequest"
}
然后,您可以代表发出请求的用户查询图表 API。访问令牌作为参数传入,您可以将其作为 header 添加到 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 身份验证模式运行,这意味着它 运行 作为应用程序而不是在特定用户的上下文中。