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

使用Microsoft Graph认证通过直接链接下载SharePoint文档遇401问题求助

将SharePoint CSOM应用迁移至Microsoft Graph API的认证问题

我正在把SharePoint CSOM应用迁移到Microsoft Graph API。原程序通过CSOM的用户名+密码凭证,借助System.Net.WebClient库下载SharePoint文档,但不清楚如何将Microsoft Graph的认证信息传递给SharePoint。

原CSOM代码

ClientContext SharePoint;
remotePath = "https://{tenant}.sharepoint.com/sites/{site}/{list}/{filename}";
localPath = "C:\\temp\\{filename}";

//Authentication in CSOM using username/password not shown

using (var client = new System.Net.WebClient())
{
    client.Credentials = SharePoint.Credentials;
    client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
    client.DownloadFileTaskAsync(remotePath, localPath).Wait();
}

尝试的Microsoft Graph代码

var parentWindowHandle = new System.Windows.Interop.WindowInteropHelper(App.Current.MainWindow).Handle;
var credentialOptions = new Azure.Identity.Broker.InteractiveBrowserCredentialBrokerOptions(parentWindowHandle)
{
    ClientId = clientId,
    TenantId = tenantId,
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

credential = new Azure.Identity.InteractiveBrowserCredential(credentialOptions);    
GraphServiceClient graphClient = new GraphServiceClient(credential);
remotePath = "https://{tenant}.sharepoint.com/sites/{site}/{list}/{filename}";
localPath = "C:\\temp\\{filename}";

var tokenRequestContext = new Azure.Core.TokenRequestContext(new[] { "https://graph.microsoft.com/.default" });
token = await credential.GetTokenAsync(tokenRequestContext);

using (var client = new System.Net.WebClient())
{
    client.Headers.Add("Authorization", "Bearer " + token.Token);
    client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
    client.DownloadFileTaskAsync(remotePath, localPath).Wait();
}

遇到的问题

执行后返回401 UNAUTHORIZED:

  • 尝试过获取https://{tenant}.sharepoint.com/.default范围的token,结果相同;
  • 试过添加/移除User-Agent: Other和X-FORMS_BASED_AUTH_ACCEPTED请求头,问题依旧;
  • 将GetTokenAsync返回的token放入Postman测试,同样返回通用401。

当前已在应用中添加多个SharePoint相关API权限(如Sites.Read.All、Files.Read.All等)。


问题解决方法

1. 正确获取SharePoint资源的Token

直接访问SharePoint站点的文件URL,需要的是针对SharePoint资源的Token,而非Graph API的Token:

  • 修改Token请求的范围为SharePoint的具体权限,而非.default(.default多用于客户端凭证流,交互式认证推荐用具体权限):
var tokenRequestContext = new Azure.Core.TokenRequestContext(new[] { 
    "https://{tenant}.sharepoint.com/Sites.Read.All", 
    "https://{tenant}.sharepoint.com/Files.Read.All" 
});
token = await credential.GetTokenAsync(tokenRequestContext);

2. 推荐:直接使用Microsoft Graph API下载文件

既然迁移到Graph,建议遵循Graph的规范,通过Graph API端点获取文件内容,而非直接访问SharePoint原始URL:

// 1. 先获取站点ID(示例:通过站点路径获取)
var site = await graphClient.Sites["{tenant}.sharepoint.com:/sites/{site}"].Request().GetAsync();
var siteId = site.Id;

// 2. 获取文件对应的DriveItem ID(示例:从列表项获取)
var listItem = await graphClient.Sites[siteId].Lists["{list-id}"].Items["{item-id}"].Request().Expand("driveItem").GetAsync();
var driveItemId = listItem.DriveItem.Id;

// 3. 下载文件到本地
using (var stream = await graphClient.Sites[siteId].Drive.Items[driveItemId].Content.Request().GetAsync())
{
    using (var fileStream = new FileStream(localPath, FileMode.Create))
    {
        await stream.CopyToAsync(fileStream);
    }
}

3. 权限配置检查

确保应用已正确添加并授予Delegated类型的SharePoint权限(因为使用的是交互式认证流):

  • 必需权限:Sites.Read.All、Files.Read.All(根据需求选择读写权限)
  • 若为租户级权限,需完成管理员同意操作。

内容的提问来源于stack exchange,提问作者General Un-Co

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:04:59