如何通过MSAL认证与Azure Functions验证用户邮箱并获取全名
解决方案:验证租户内有效用户并获取全名
核心方案
通过Microsoft Graph API + On-Behalf-Of (OBO)流程实现:后端Azure Function使用前端传来的用户访问令牌,向Azure AD申请Graph API的访问权限,再调用Graph的/users端点根据邮箱查询用户信息——既验证邮箱是否为租户内有效用户,又能直接获取用户全名。
前提准备
- 确保你的Azure AD应用注册已授予委托权限
user.ReadBasic.All,并完成管理员同意(因为需要查询租户内其他用户)。 - 在Azure Function中安装依赖:
npm install @azure/msal-node @microsoft/microsoft-graph-client isomorphic-fetch
修改后的Azure Function代码
const { ConfidentialClientApplication } = require('@azure/msal-node'); const { Client } = require('@microsoft/microsoft-graph-client'); const { TokenCredentialAuthenticationProvider } = require('@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials'); const fetch = require('isomorphic-fetch'); // 配置MSAL客户端(对应Azure AD应用注册的后端应用信息) const msalConfig = { auth: { clientId: "YOUR_BACKEND_APP_CLIENT_ID", clientSecret: "YOUR_BACKEND_APP_CLIENT_SECRET", authority: "https://login.microsoftonline.com/YOUR_TENANT_ID" } }; const cca = new ConfidentialClientApplication(msalConfig); const tenantId = "YOUR_TENANT_ID"; module.exports = async function (context, req) { if (req.method === 'POST') { try { const { email } = req.body; const token = req.headers.authorization; if (!token || !email) { context.res = { status: 400, body: JSON.stringify({ error: "Token in 'Authorization' header and email in request body are required." }) }; return; } const bearerToken = token.split(' ')[1]; // 1. OBO流程获取Graph API的访问令牌 const oboRequest = { oboAssertion: bearerToken, scopes: ["https://graph.microsoft.com/user.ReadBasic.All"], }; const oboResponse = await cca.acquireTokenOnBehalfOf(oboRequest); if (!oboResponse || !oboResponse.accessToken) { context.res = { status: 403, body: JSON.stringify({ error: 'Failed to acquire Graph API token' }) }; return; } // 2. 调用Graph API查询用户 const graphClient = Client.initWithMiddleware({ authProvider: new TokenCredentialAuthenticationProvider({ getToken: async () => ({ token: oboResponse.accessToken, expiresOnTimestamp: Date.now() + oboResponse.expiresIn * 1000 }) }), fetchProvider: () => fetch }); try { // 根据邮箱查询用户,$select指定需要的字段 const user = await graphClient.api(`/users/${encodeURIComponent(email)}`).select('displayName,mail').get(); // 返回验证成功的信息及用户全名 context.res = { status: 200, body: JSON.stringify({ message: 'Email is a valid tenant user.', fullName: user.displayName, userEmail: user.mail }) }; } catch (graphError) { // Graph返回404表示用户不存在 if (graphError.statusCode === 404) { context.res = { status: 400, body: JSON.stringify({ error: 'Email is not a valid user in the tenant.' }) }; } else { context.log.error('Graph API error:', graphError.message); context.res = { status: 500, body: JSON.stringify({ error: 'Failed to verify user via Graph API' }) }; } } } catch (error) { context.log.error('Token verification error:', error.message); context.res = { status: 401, body: JSON.stringify({ error: 'Invalid token' }) }; } } else { context.res = { status: 405, body: JSON.stringify({ error: "Method Not Allowed" }) }; } };
关键说明
- OBO流程:后端用用户的访问令牌换取Graph API的专用令牌,确保调用Graph的权限是基于当前登录用户的委托权限。
- Graph API查询:使用
/users/{email}端点精准查询,若返回404则判定为无效用户,200则提取displayName作为全名。 - 权限保障:
user.ReadBasic.All委托权限允许登录用户查询租户内所有用户的基本信息,完全覆盖需求场景。
内容的提问来源于stack exchange,提问作者Snooper_A
相关产品推荐
相关产品推荐

