我正在开发一个与 Azure Active Directory Graph API (@azure/graph) 交互的 Azure Function。该函数 API 旨在验证电子邮件是否在 Azure AD(Entra Id)中注册和验证。但是,我遇到了访问令牌丢失或格式错误的问题。
当该函数尝试向 Graph API 发出请求以通过电子邮件获取用户时 (
graphClient.users.list
),它会抛出以下错误:
注意:我正在使用 postman 来测试 api
http://localhost:7071/api/checkEmail
Error verifying email: RestError: {"odata.error":{"code":"Authentication_MissingOrMalformed","codeForMetrics":"Authentication_MissingOrMalformed","message":{"lang":"en","value":"Access Token missing or malformed."}}}
尽管使用 @azure/identity 中的 DefaultAzureCredential 来获取令牌,但仍会发生这种情况。 我已检查我的 Azure AD 配置和环境变量
(AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)
,这似乎是正确的。
这是我的 Azure Function 代码的相关部分:
const { GraphRbacManagementClient } = require("@azure/graph");
const { DefaultAzureCredential } = require("@azure/identity");
const tenantId = process.env.AZURE_TENANT_ID;
module.exports = async function (context, req) {
context.log('Checking if email is verified...');
const { email } = req.body;
if (!email) {
context.res = {
status: 400,
body: "Please provide the email"
};
return;
}
try {
const credential = new DefaultAzureCredential();
const graphClient = new GraphRbacManagementClient(
credential,
tenantId
);
const verifyEmail = async (email) => {
try {
const users = await graphClient.users.list({ filter: `mail eq '${email}'` });
const user = users.next().value;
if (user) {
if (user.mailVerified) {
return true;
} else {
return false;
}
} else {
return false;
}
} catch (error) {
console.error("Error verifying email:", error);
return false;
}
};
const isEmailVerified = await verifyEmail(email);
if (isEmailVerified) {
context.res = {
status: 200,
body: "Email is verified"
};
} else {
context.res = {
status: 400,
body: "Email is not verified or does not exist"
};
}
} catch (error) {
console.error("Error:", error);
context.res = {
status: 500,
body: "Internal Server Error"
};
}
};
此外,我已经尝试直接使用 ClientSecretCredential 而不是 DefaultAzureCredential,但问题仍然存在。 Azure AD 权限似乎已正确配置用于应用程序注册。
什么可能导致我的 Azure Functions 中出现“访问令牌丢失或格式错误”错误?如何确保正确获取访问令牌并将其用于通过 Graph API 进行身份验证?
任何见解或建议将不胜感激。谢谢!
根据您的错误代码,您的访问令牌是恶意的,尝试使用下面的代码使用Client Credentials Flow
成功生成访问令牌:-
const axios = require('axios');
async function getToken(tenantId, clientId, clientSecret, scope) {
try {
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const requestBody = {
client_id: clientId,
scope: scope,
client_secret: clientSecret,
grant_type: 'client_credentials'
};
const response = await axios.post(tokenEndpoint, new URLSearchParams(requestBody), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
if (response.status === 200) {
return response.data.access_token;
} else {
throw new Error('Failed to retrieve access token');
}
} catch (error) {
console.error('Error getting token:', error.message);
throw error;
}
}
const tenantId = '8xxxxxxxx2395';
const clientId = 'cxxxxxxxxx5cb';
const clientSecret = 'vxxxxxxxNq9hD6bsf';
const scope = 'https://graph.microsoft.com/.default';
(async () => {
try {
const accessToken = await getToken(tenantId, clientId, clientSecret, scope);
console.log('Access token:', accessToken);
} catch (error) {
console.error('Error:', error.message);
}
})();
输出:-
访问令牌已成功生成:-
功能码:-
在下面的功能代码中使用上面的访问令牌:-
const { app } = require('@azure/functions');
const axios = require('axios');
// Define the HTTP trigger function
app.http('httpTrigger1', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
try {
// Fetch user profile from Microsoft Graph API
const accessToken = 'xxxxxxxxxxxxxxqg'; // Replace with actual access token obtained using client credentials flow
const userId = '8f1dbxxxxxx5e5d8f9a5d'; // Replace with the user's ID
const profileResponse = await axios.get(`https://graph.microsoft.com/v1.0/users/${userId}`, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
// Return entire output from the profile response
return {
status: 200,
body: profileResponse.data
};
} catch (error) {
context.log(`Error fetching user profile: ${error}`);
return {
status: 500,
body: "Internal Server Error"
};
}
}
});
输出:-