You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MS Graph复制DriveItem后遇Invalid Audience授权错误咨询

问题

向MS Graph发起Copy请求后,需要获取对应的driveItem。按照文档要求,处理请求头Location获取复制流程的监控地址,使用AsyncMonitor<DriveItem>及其PollForOperationCompletionAsync方法,但复制完成后收到authorization error: Invalid Audience错误。推测原因是复制成功后asyncMonitor重定向到了SharePoint REST API的资源地址(格式为https://{tenant-name}.sharepoint.com/_api/v2.0/drives/{drive-id}/items/{driveItem})。

需要明确两个问题:

  1. 为何使用MS Graph API却会返回SharePoint REST API的资源?
  2. 是否需要进行令牌交换等操作?

代码示例:

var copyResponse = await client.Sites[siteId].Lists[listId].Drive.Items[file.DriveItemId]
        .Copy(file.Name, reference)
        .Request()
        .PostResponseAsync();

var locationHeader = copyResponse.HttpHeaders.Location;
if (locationHeader == null)
{
    return null;
}

if (!locationHeader.IsAbsoluteUri)
{
    locationHeader = new Uri(client.BaseUrl + locationHeader.OriginalString);
}

IProgress<AsyncOperationStatus> progress = new Progress<AsyncOperationStatus>(operationStatus =>
{
    logger.LogInformation(
        $"Copying file {file.Name} status: {operationStatus.Status}");
});

var asyncMonitor = new AsyncMonitor<DriveItem>(client, locationHeader.AbsoluteUri);
var result =  await asyncMonitor.PollForOperationCompletionAsync(progress, CancellationToken.None);
回答

为什么会返回SharePoint REST API的资源?

MS Graph是统一的API入口,但底层处理文档库类操作(比如文件复制)时,会依赖SharePoint原生REST API。当异步复制完成后,MS Graph的监控端点会直接重定向到SharePoint REST的资源地址——这是因为最终的driveItem数据实际存储在SharePoint后端,直接返回原生地址能减少转发开销,提升效率。

但问题出在令牌受众不匹配:你当前使用的MS Graph令牌,受众(audience)是https://graph.microsoft.com,而SharePoint REST API要求令牌的受众是对应的SharePoint站点域名(比如https://{tenant-name}.sharepoint.com),所以用Graph令牌访问SharePoint REST地址就会触发Invalid Audience错误。

是否需要令牌交换?

是的,但更简便的方式是避开直接访问SharePoint REST地址,改用MS Graph端点获取最终的driveItem:

  1. 优先用Graph查询替代重定向地址:当监控到复制状态变为Completed时,直接通过MS Graph的drives/{drive-id}/items/{item-id}端点查询目标文件,不需要处理重定向后的SharePoint地址。
  2. 令牌交换(备选方案):如果一定要用重定向地址,需要用当前Graph令牌的刷新令牌,向Azure AD请求受众为目标SharePoint站点的新令牌,再用新令牌访问该地址。但这种方式步骤繁琐,不如直接用Graph查询高效。

优化后的代码示例

修改逻辑,在复制完成时直接通过Graph API获取目标文件:

var copyResponse = await client.Sites[siteId].Lists[listId].Drive.Items[file.DriveItemId]
        .Copy(file.Name, reference)
        .Request()
        .PostResponseAsync();

var locationHeader = copyResponse.HttpHeaders.Location;
if (locationHeader == null)
{
    return null;
}

if (!locationHeader.IsAbsoluteUri)
{
    locationHeader = new Uri(client.BaseUrl + locationHeader.OriginalString);
}

DriveItem result = null;
IProgress<AsyncOperationStatus> progress = new Progress<AsyncOperationStatus>(async operationStatus =>
{
    logger.LogInformation($"Copying file {file.Name} status: {operationStatus.Status}");
    
    // 复制完成时,直接通过Graph查询目标文件
    if (operationStatus.Status == AsyncOperationStatusState.Completed)
    {
        // 从ResourceLocation中解析目标item的ID和driveID,转换为Graph端点格式
        var resourceUri = new Uri(operationStatus.ResourceLocation);
        // 提取路径中的drives/{driveId}/items/{itemId}部分
        var graphPath = resourceUri.PathAndQuery.Replace("/_api/v2.0/", "/v1.0/");
        result = await client.HttpProvider.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"https://graph.microsoft.com{graphPath}"))
            .ContinueWith(t => t.Result.Content.ReadAsAsync<DriveItem>().Result);
    }
});

var asyncMonitor = new AsyncMonitor<DriveItem>(client, locationHeader.AbsoluteUri);
await asyncMonitor.PollForOperationCompletionAsync(progress, CancellationToken.None);

return result;

内容的提问来源于stack exchange,提问作者Kavrat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:40:52