MS Graph Beta API条件访问策略监控:GUID替换与权限范围咨询
关于MS Graph Beta API获取条件访问策略时替换GUID为名称的问题
我正在开发监控条件访问策略的仪表板API查询,调用接口正常,但返回结果里的用户和角色都是GUID(见示例输出),实用性很差。
示例输出
{ "id": "8193577f-eed0-4dcd-8570-bea5dde99caf", "templateId": "c7503427-338e-4c5e-902d-abe252abfb43", "displayName": "Require multifactor authentication for admins", "createdDateTime": "2025-02-18T16:45:43.440382Z", "modifiedDateTime": null, "state": "enabled", "partialEnablementStrategy": null, "sessionControls": null, "conditions": { "userRiskLevels": [], "signInRiskLevels": [], "clientAppTypes": ["all"], "platforms": null, "locations": null, "times": null, "deviceStates": null, "devices": null, "clientApplications": null, "applications": { "includeApplications": ["All"], "excludeApplications": [], "includeUserActions": [], "includeAuthenticationContextClassReferences": [], "applicationFilter": null }, "users": { "includeUsers": [], "excludeUsers": [ "2c5b3083-c60b-41ad-9343-eb3bc01d444a" // GUID格式用户ID ], "includeGroups": [], "excludeGroups": [], "includeRoles": [ "62e90394-69f5-4237-9190-012177145e10", // GUID格式角色ID "194ae4cb-b126-40b2-bd5b-6091b380977d", "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", "29232cdf-9323-42fd-ade2-1d097af3e4de", "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", "729827e3-9c14-49f7-bb1b-9608f156bbb8" ] } } }
核心问题
使用MS Graph Beta API,除了Directory.Read.All和Policies.Read.All权限,有没有额外权限能让接口直接返回用户/角色的名称?还是必须提取所有ID后手动匹配回填?
我的API调用代码
const handleGetPolicies = async () => { if (isAuthenticated) { setIsFetching(true); try { // 获取条件访问策略 const result = await callMsGraph('/policies/conditionalAccessPolicies'); // 待实现的替换逻辑函数 const updatedResult = await replaceUserIdsWithDisplayNames(result); setResponse(JSON.stringify(updatedResult, null, 2)); } catch (error) { setResponse('获取策略失败: ' + (error as Error).message); } setIsFetching(false); } else { setResponse('用户未认证'); } };
解答
目前MS Graph Beta的/policies/conditionalAccessPolicies接口不支持直接返回用户/角色的名称,无论添加什么额外权限都无法实现。你必须手动提取GUID,单独调用API获取对应名称后回填到结果中。
具体实现步骤
- 收集所有需要替换的ID:遍历每个策略的
conditions.users字段,收集includeUsers、excludeUsers、includeRoles、excludeRoles里的所有GUID(跳过"All"这类特殊值)。 - 批量查询用户和角色信息:
- 查询用户:调用
/users?$filter=id in ('guid1','guid2')&$select=id,displayName,批量获取用户ID对应的显示名称。 - 查询目录角色:调用
/directoryRoles?$filter=id in ('guid1','guid2')&$select=id,displayName,注意CA策略中的角色ID是目录角色实例的ID,而非角色定义ID。
- 查询用户:调用
- 建立映射表并替换:将查询到的ID和名称存入对象映射,遍历原策略结果,把所有GUID替换为对应的名称。
替换函数示例代码
const replaceUserIdsWithDisplayNames = async (policies) => { // 收集所有需要查询的ID const userIds = new Set(); const roleIds = new Set(); policies.forEach(policy => { const { users } = policy.conditions || {}; if (!users) return; // 收集用户ID [...(users.includeUsers || []), ...(users.excludeUsers || [])] .filter(id => id !== 'All' && id !== 'None') .forEach(id => userIds.add(id)); // 收集角色ID [...(users.includeRoles || []), ...(users.excludeRoles || [])] .filter(id => id !== 'All' && id !== 'None') .forEach(id => roleIds.add(id)); }); // 批量查询用户 const userMap = {}; if (userIds.size > 0) { const userIdsArr = Array.from(userIds); // 分批处理,因为in操作符最多支持15个ID const batches = []; for (let i = 0; i < userIdsArr.length; i += 15) { batches.push(userIdsArr.slice(i, i + 15)); } for (const batch of batches) { const filter = `id in (${batch.map(id => `'${id}'`).join(',')})`; const users = await callMsGraph(`/users?$filter=${filter}&$select=id,displayName`); users.value.forEach(user => { userMap[user.id] = user.displayName; }); } } // 批量查询角色 const roleMap = {}; if (roleIds.size > 0) { const roleIdsArr = Array.from(roleIds); const batches = []; for (let i = 0; i < roleIdsArr.length; i += 15) { batches.push(roleIdsArr.slice(i, i + 15)); } for (const batch of batches) { const filter = `id in (${batch.map(id => `'${id}'`).join(',')})`; const roles = await callMsGraph(`/directoryRoles?$filter=${filter}&$select=id,displayName`); roles.value.forEach(role => { roleMap[role.id] = role.displayName; }); } } // 替换原结果中的GUID return policies.map(policy => { const newPolicy = { ...policy }; const { users } = newPolicy.conditions || {}; if (!users) return newPolicy; // 替换用户ID ['includeUsers', 'excludeUsers'].forEach(field => { if (users[field]) { users[field] = users[field].map(id => userMap[id] || id); } }); // 替换角色ID ['includeRoles', 'excludeRoles'].forEach(field => { if (users[field]) { users[field] = users[field].map(id => roleMap[id] || id); } }); return newPolicy; }); };
注意事项
- 批量查询时,
$filter=id in()最多支持15个ID,超过需要分批处理。 - 确保已申请
Directory.Read.All权限,否则无法查询用户和目录角色信息。 - 可以添加缓存逻辑,对已查询过的ID进行缓存,避免重复调用API提升性能。
内容的提问来源于stack exchange,提问作者Sethe23
相关产品推荐
相关产品推荐

