如何通过AadHttpClient在Azure Function中识别SPFx WebPart调用用户
注意:下文提及的Azure Function和SPFx WebPart均基于NodeJS/JavaScript编写,未使用C#。
我有一个由AAD(应用注册)保护的Azure Function,通过SharePoint页面上的SPFx WebPart使用AadHttpClient进行调用,SPFx代码如下:
return new Promise<void>((resolve: () => void, reject: (error: any) => void): void => { this.context.aadHttpClientFactory.getClient("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") // <--- 这是AAD客户端应用ID .then((client: AadHttpClient): void => { client.post("https://myAzureFunctionName.azurewebsites.net/api/HttpTrigger1", AadHttpClient.configurations.v1, { body: JSON.stringify({ data: someData }) }) .then((res: HttpClientResponse): Promise<any> => { return res.json(); }) .then((response: any): void => { console.log("SUCCESSFUL API RESPONSE:", response); // <--- 此时已成功获取Azure Function的响应 resolve(); }, (err: any): void => { console.error(err); }); }, err => reject(err)); });
目前调用正常,但在Azure Function端无法正确识别调用API的当前SharePoint用户。我想到的临时办法是将从_spPageContextInfo对象中获取的用户信息(如邮箱地址)附加到API请求中发送给Azure Function。
请问:从Azure Function端出发,通过AadHttpClient识别SPFx WebPart的当前登录终端用户的正规、可信方式是什么?以便我能在Azure Function中使用该用户的邮箱地址。
要在Node.js版Azure Function中可信地识别SPFx端的当前登录用户,核心是利用AAD OAuth2的用户委派令牌——AadHttpClient默认会将当前SharePoint用户的委派令牌附加到请求的Authorization头中,你需要在Azure Function中解析这个令牌来获取用户信息,步骤如下:
1. 确认Azure Function的AAD认证配置
确保你的Azure Function对应的应用注册已正确配置:
- 已为SPFx的客户端应用(即
getClient中传入的应用ID)授予委派权限(通常是user_impersonation权限) - 该委派权限已获得管理员同意
2. 在Azure Function中解析并验证JWT令牌
AadHttpClient发送的请求会携带Bearer <JWT_TOKEN>格式的Authorization头,你可以提取并解析这个令牌获取用户信息,生产环境必须验证令牌的合法性:
基础解析(仅用于测试)
const jwt = require('jsonwebtoken'); module.exports = async function (context, req) { // 提取授权头中的令牌 const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { context.res = { status: 401, body: '未提供有效的用户令牌' }; return; } const token = authHeader.split(' ')[1]; try { // 解析令牌(测试用,生产环境必须验证签名) const decodedToken = jwt.decode(token); // 从令牌声明中获取用户邮箱(优先取email,无则取upn) const userEmail = decodedToken.email || decodedToken.upn; const userId = decodedToken.oid; // 用户的AAD对象ID context.log(`当前调用用户:${userEmail}`); // 后续业务逻辑使用用户信息 context.res = { status: 200, body: { message: `欢迎,${userEmail}`, userId: userId } }; } catch (err) { context.res = { status: 401, body: '令牌解析失败' }; } };
生产环境的完整验证
必须验证令牌的签名、有效期、受众、发行者等,确保令牌可信:
const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); // 初始化JWKS客户端,从Azure AD获取公钥用于验证签名 const client = jwksClient({ jwksUri: 'https://login.microsoftonline.com/{你的租户ID}/discovery/v2.0/keys' }); function getSigningKey(header, callback) { client.getSigningKey(header.kid, function(err, key) { const signingKey = key.getPublicKey(); callback(null, signingKey); }); } module.exports = async function (context, req) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { context.res = { status: 401, body: '无效的授权头' }; return; } const token = authHeader.split(' ')[1]; jwt.verify(token, getSigningKey, { audience: '你的Azure Function应用注册的客户端ID', // 令牌受众必须匹配Function的应用ID issuer: 'https://login.microsoftonline.com/{你的租户ID}/v2.0', // 令牌发行者 algorithms: ['RS256'] // AAD v2.0令牌使用RS256算法签名 }, function(err, decoded) { if (err) { context.res = { status: 401, body: '令牌验证失败:' + err.message }; return; } // 验证通过,获取可信的用户信息 const userEmail = decoded.email || decoded.upn; context.res = { status: 200, body: `用户邮箱:${userEmail}` }; }); };
为什么不推荐手动传用户信息?
手动从_spPageContextInfo提取用户信息并发送存在安全风险——恶意用户可以篡改请求中的用户信息,而通过解析AAD颁发的委派令牌,令牌本身经过加密签名,无法篡改,能保证用户身份的可信性。
内容的提问来源于stack exchange,提问作者夏期劇場

