Microsoft Graph REST API获取长时操作状态遇401未授权问题
问题场景
我通过Microsoft Graph REST API执行driveItem: copy操作,请求如下:
POST /sites/{siteId}/drive/items/{itemId}/copy
请求执行成功,但由于是长时间运行进程,直接查询刚复制的driveItem时发现资源尚未创建。按照官方指引,我向响应返回的Location URI发送GET请求查询操作状态,示例URI:
GET https://api.onedrive.com/monitor/4A3407B5-88FC-4504-8B21-0AABD3412717
但实际收到的是401“未授权”响应。我已尝试携带/不携带认证令牌两种方式,使用Azure Entra ID应用密钥认证,且已配置Sites.Read.All等所需权限,官方文档说明查询状态的权限与执行操作的权限一致,但问题仍未解决。相关代码片段:
... // 复制请求(执行成功) var copyResponseMessage = await _httpClient.SendAsync(copyRequestMessage); if (copyResponseMessage.IsSuccessStatusCode) { string uri = copyResponseMessage.Headers.Location?.AbsoluteUri; // 实际获取到的uri:https://[ourTenant].sharepoint.com/sites/[ourSiteName]/_api/v2.1/drive/operations/[operationId] var statusRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri); var statusResponseMessage = await _httpClient.SendAsync(statusRequestMessage); // 结果:statusResponseMessage.StatusCode == HttpStatusCode.Unauthorized } ...
更新(2024/3/18):我认为包括长时间运行操作端点在内的各类Graph API beta端点不可靠,不适合在生产环境使用。
可行解决方向
1. 匹配令牌受众与端点域名
你获取的Azure Entra ID令牌的aud(受众)声明必须和状态查询端点的域名匹配。如果是SharePoint站点内的/_api/v2.1/drive/operations/[operationId]端点,令牌的aud应该是https://[tenant].sharepoint.com,而非通用的https://graph.microsoft.com。应用密钥认证时,获取令牌的scope要指定对应的SharePoint资源,比如https://[tenant].sharepoint.com/.default,而非https://graph.microsoft.com/.default。
2. 确保请求携带正确认证令牌
不要尝试不携带令牌访问该端点——长时间运行操作的状态查询必须授权,未携带令牌必然返回401。检查你的_httpClient是否自动附加了正确的Bearer令牌,或者手动添加Authorization头:
statusRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", yourAccessToken);
3. 验证权限范围是否足够
虽然你配置了Sites.Read.All,但复制操作属于写入操作,可能需要Sites.ReadWrite.All权限,而状态查询的权限要求和执行操作的权限一致。确认应用注册的权限是否包含Sites.ReadWrite.All且已完成管理员同意授权。
4. 改用Graph标准状态查询端点
你实际获取的Location是SharePoint的/_api/v2.1非标准端点,建议改用Graph API v1.0正式版的统一操作状态查询端点:
GET /sites/{siteId}/drive/operations/{operationId}
这个端点稳定性更高,使用Graph的认证令牌即可访问,避免跨端点的权限适配问题。
生产环境建议
确实应优先使用Graph API的v1.0正式端点,beta端点仅用于测试新功能,存在不可靠、随时变更的风险。如果需要处理长时间运行的复制操作,除了轮询状态,还可以设置webhook通知,当复制完成时接收事件推送,这比轮询更高效可靠。
内容的提问来源于stack exchange,提问作者Nelson Nyland

