启用应用身份验证的Azure Functions(Node.js)调用Microsoft Graph遇阻
解决Azure Functions调用Microsoft Graph API的两个核心问题
我来帮你拆解你遇到的两个问题:HTTP 404绑定失效和访问令牌受众错误,这俩问题是不同原因导致的,咱们一步步捋清楚解决。
一、先搞定最关键的:"Access token validation failure. Invalid audience." 错误
你这里踩了一个很常见的坑:你用的是ID令牌(x-ms-token-aad-id-token)去调用Graph API,但Graph需要的是专门针对它的访问令牌。
为什么会报错?
x-ms-token-aad-id-token是ID令牌,它的受众(aud字段)是你的Azure Functions应用注册的客户端ID,作用是验证用户身份,根本不能直接用来调用Graph API。- Graph API要求访问令牌的受众必须是
https://graph.microsoft.com,用ID令牌凑数肯定会触发受众验证失败。
正确姿势:用On-Behalf-Of(OBO)流程换取Graph访问令牌
因为你的Function是代表当前登录用户调用Graph,所以得用用户的ID令牌去换Graph的访问令牌,具体步骤如下:
配置AAD应用注册
- 给你的Function App对应的AAD应用注册添加Graph的委托权限(比如
User.Read),记得要授予管理员同意。 - 记下应用的
客户端ID、客户端密钥和租户ID,后面代码要用到。
- 给你的Function App对应的AAD应用注册添加Graph的委托权限(比如
修改Function代码实现OBO流程
先装依赖:npm install @azure/msal-node @microsoft/microsoft-graph-client @microsoft/microsoft-graph-client/authProviders/azureTokenCredentials替换你的函数代码:
const { ConfidentialClientApplication } = require('@azure/msal-node'); const graph = require('@microsoft/microsoft-graph-client'); const { TokenCredentialAuthenticationProvider } = require('@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials'); module.exports = async function (context, req) { // 获取用户的ID令牌 const idToken = req.headers['x-ms-token-aad-id-token']; if (!idToken) { context.res = { status: 400, body: '缺少用户身份令牌' }; return; } // 配置MSAL,替换成你的应用信息 const msalConfig = { auth: { clientId: '你的Function App客户端ID', clientSecret: '你的Function App客户端密钥', authority: 'https://login.microsoftonline.com/你的租户ID' } }; const cca = new ConfidentialClientApplication(msalConfig); try { // 执行OBO流程,拿到Graph访问令牌 const oboRequest = { oboAssertion: idToken, scopes: ['https://graph.microsoft.com/User.Read'], // 按需加需要的Graph权限 skipCache: true }; const tokenResponse = await cca.acquireTokenOnBehalfOf(oboRequest); const graphAccessToken = tokenResponse.accessToken; // 初始化Graph客户端 const client = graph.Client.init({ authProvider: new TokenCredentialAuthenticationProvider({ getToken: async () => ({ token: graphAccessToken, expiresOnTimestamp: Date.now() + 3600 * 1000 }) }) }); // 调用Graph API const user = await client.api('/me').get(); context.log('获取用户信息成功:', user); context.res = { status: 200, body: user }; } catch (error) { context.log.error('调用Graph API失败:', error); context.res = { status: 500, body: `错误详情: ${error.message || JSON.stringify(error)}` }; } };
二、解决HTTP 404绑定失效问题
这个问题大概率和路由配置或身份验证后的重定向有关,你可以按下面的步骤排查:
- 检查函数路由配置:打开函数的
function.json,确认route属性是否正确(没设置的话默认是api/函数名),部署后的路由和本地调试的路由要一致。 - 验证身份验证配置:在Azure门户的Function App身份验证设置里,确保:
- 没开启"允许匿名请求"
- AAD身份提供者的客户端ID、租户ID和你应用注册的信息完全匹配
- 浏览器调用方式:开了AAD身份验证后,直接在浏览器访问函数URL,会自动跳转到AAD登录页,登录成功后应该能正常访问;要是还是404,检查函数是不是部署错了(比如漏了文件,或者部署日志有报错)。
- 手动调用注意事项:手动测试的时候,要把
x-ms-token-aad-id-token放在请求头里,别放到Authentication: Bearer xxx里,因为Functions的身份验证中间件是靠x-ms-token-aad-id-token识别用户令牌的。
最后再提醒几个关键点
- 一定要确保Function App的应用注册已经拿到了Graph权限的管理员同意,不然OBO流程会直接失败。
- 别把客户端密钥硬写在代码里,建议用Azure Functions的应用设置(环境变量)存,比如
process.env.CLIENT_SECRET。
内容的提问来源于stack exchange,提问作者monsty
相关产品推荐
相关产品推荐

