使用 .net api 更新 google 云存储对象元数据因禁止错误而失败

Update google cloud storage object meta with .net api failed with forbidden error

我正在尝试使用 .net 客户端更新现有 google 云存储对象的元数据。但是,我总是遇到 Fobidden 错误。错误信息是:

Google.Apis.Requests.RequestError
Forbidden [403]
Errors [
    Message[Forbidden] Location[ - ] Reason[forbidden] Domain[global]
]

我使用的代码是:

    private void UpdateMeta(string key)
    {
        var service = Connect();
        var req = service.Objects.Get(bucketName, key);
        GCSObject readobj = req.Execute();
        readobj.Bucket = bucketName;
        if (readobj.Metadata == null)
        {
            readobj.Metadata = new Dictionary<string, string>();
        }
        readobj.Metadata["x-goog-meta-test"] = DateTime.Now.ToString();
        service.Objects.Patch(readobj, readobj.Bucket, key).Execute();
    }

我的代码有问题吗?

连接方法是:

    private StorageService Connect()
    {
        string serviceAccountEmail = "account_id@developer.gserviceaccount.com";
        var certificate = GetGCSCertificate(); // retrive the x509 certificate file
        ServiceAccountCredential credential = new ServiceAccountCredential(
           new ServiceAccountCredential.Initializer(serviceAccountEmail)
           {
               Scopes = new[] { StorageService.Scope.DevstorageReadWrite }
           }.FromCertificate(certificate));
        var service = new StorageService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = "GCS Sample",
        });
        return service;
    }

这里是gsutil命令发送的http请求。它成功更新了元数据。

PATCH https://www.googleapis.com/storage/v1/b/BUCKETNAME/o/OBJECTNAME?ifMetagenerationMatch=1&ifGenerationMatch=1429863183870000&projection=full&prettyPrint=True&alt=json HTTP/1.1
Host: www.googleapis.com
Content-length: 128
Accept-encoding: gzip, deflate
Accept: application/json
User-agent: apitools gsutil/4.11 (win32)
Content-type: application/json
Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

{"generation": "1429863183870000", "metageneration": "1", "metadata": {"test": "2015- sdf2", "key2": "4/24/2015 8:12:58 AM"}}

这里是c#客户端发送的http请求。失败了。

PATCH https://www.googleapis.com/storage/v1/b/BUCKETNAME/o/OBJECTNAME?ifMetagenerationMatch=2&ifGenerationMatch=1429863183870000&projection=full&prettyPrint=True HTTP/1.1
User-Agent: GCS Sample google-api-dotnet-client/1.9.0.26010 (gzip)
Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json; charset=utf-8
Host: www.googleapis.com
Content-Length: 116
Accept-Encoding: gzip

{"generation":1429863183870000,"metadata":{"key2":"4/24/2015 8:23:52 AM","test":"2015- sdf2"},"metageneration":2}

我看不出这两个 http 请求有什么区别。


我找出了禁止错误的根本原因。这是因为我使用了错误的范围设置。在 Connect 方法中,而不是

           Scopes = new[] { StorageService.Scope.DevstorageReadWrite }

我们应该使用

           Scopes = new[] { StorageService.Scope.DevstorageFullControl }

您确定您的应用程序对该对象具有读取权限吗?您可以定义两种类型的 ACL:存储桶和对象。要读取一个对象,您需要该对象的读取权限。要列出存储桶中的对象,您需要对存储桶具有读取权限。

该代码看起来不错,但我看不出您是如何验证您的请求的。如果您的呼叫是匿名进行的,则访问私有对象将失败。要了解如何授权您的请求,请尝试 https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth

还要考虑 Shobhit 的回答。无论您使用哪个帐户读取对象,都必须具有该对象的读取权限。允许公开访问一个对象,在这种情况下,匿名用户可以阅读它。