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

C#使用Microsoft.Graph上传文件到SharePoint后如何对比本地与云端文件哈希

问题根因

你遇到的403报错原因是System.Net.WebClient没有携带你通过Microsoft Graph API认证得到的授权令牌,直接请求SharePoint的文件资源地址会被权限校验拦截。另外无需手动下载文件计算哈希,Microsoft Graph返回的DriveItem资源本身就包含官方预计算的哈希值,直接调用即可,性能更高。

正确实现步骤

1. 确认AAD应用权限

先确保你注册的AAD应用已经授予了对应SharePoint站点的以下应用权限/委托权限(根据你的应用身份选择),并完成管理员同意:

  • Files.Read.All 或 Sites.Read.All(仅读取文件元数据的最小权限)
  • 如果是上传后立即校验,你已有的上传权限(Files.ReadWrite.All/Sites.ReadWrite.All)已经足够,无需额外加权限

2. 调用Graph API获取云端文件哈希

文件上传成功后,Graph会返回对应DriveItem对象,直接取file.hashes属性即可,里面包含sha1Hash、sha256Hash、quickXorHash三种预计算的哈希值,官方推荐用quickXorHash做文件一致性校验,性能最优。

示例代码:

// 假设你已经初始化了GraphServiceClient实例,命名为graphClient
// 上传文件的代码执行后拿到driveItem对象,或者根据文件ID/路径查询
var driveItem = await graphClient
    .Sites["你的SharePoint站点ID"]
    .Drive
    .Root
    .ItemWithPath("文件在SharePoint中的相对路径")
    .Request()
    .Select("file,id,name") // 只请求需要的元数据,减少响应体积
    .GetAsync();

// 取出云端的quickXorHash值
string cloudHash = driveItem.File.Hashes.QuickXorHash;

3. 本地计算相同算法的哈希做对比

因为Graph返回的是QuickXorHash,你需要在本地用相同算法计算本地文件的哈希值,和云端返回的对比即可:

// 本地计算QuickXorHash的实现,适配.NET Framework 4.6.1
public static string ComputeQuickXorHash(string filePath)
{
    const int shift = 11;
    const int width = 160;
    ulong[] data = new ulong[(width + 63) / 64];
    int length = 0;

    using (var stream = File.OpenRead(filePath))
    {
        int shiftSoFar = 0;
        byte[] buffer = new byte[1024 * 1024];
        int bytesRead;
        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            length += bytesRead;
            for (int i = 0; i < bytesRead; i++)
            {
                int byteIndex = shiftSoFar / 8;
                int bitShift = shiftSoFar % 8;
                ulong val = buffer[i];
                data[byteIndex % (data.Length)] ^= val << bitShift;
                if (bitShift > 64 - 8)
                {
                    data[(byteIndex + 1) % data.Length] ^= val >> (64 - bitShift);
                }
                shiftSoFar = (shiftSoFar + shift) % width;
            }
        }
    }

    // 把长度信息也异或进去
    byte[] lengthBytes = BitConverter.GetBytes(length);
    for (int i = 0; i < lengthBytes.Length; i++)
    {
        data[i % data.Length] ^= (ulong)lengthBytes[i] << (8 * i);
    }

    // 转base64字符串,和Graph返回的格式一致
    byte[] hashBytes = new byte[data.Length * 8];
    for (int i = 0; i < data.Length; i++)
    {
        Buffer.BlockCopy(BitConverter.GetBytes(data[i]), 0, hashBytes, i * 8, 8);
    }
    return Convert.ToBase64String(hashBytes).TrimEnd('=');
}

4. 校验逻辑

直接对比本地计算的哈希和云端返回的哈希即可:

string localHash = ComputeQuickXorHash(@"本地文件路径");
if (localHash.Equals(cloudHash, StringComparison.Ordinal))
{
    // 文件上传一致,校验通过
}
else
{
    // 文件损坏,需要重新上传
}

可选方案:用MD5校验

如果你一定要用MD5做校验,不要用WebClient单独下载文件,而是通过Graph SDK的Content接口下载文件流,SDK会自动携带授权令牌,不会出现403报错:

using (var stream = await graphClient.Sites["站点ID"].Drive.Root.ItemWithPath("文件路径").Content.Request().GetAsync())
using (var md5 = MD5.Create())
{
    var hash = md5.ComputeHash(stream);
    string cloudMd5 = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:36:02