首页 > 解决方案 > C# 可以写入但不能读取存储库的 BitBucket API

问题描述

我正在尝试使用 C# 访问 BitBucket API。我可以执行一些操作,但不能执行其他操作。值得注意的是,写入存储库是可行的,但读取它们却不行。

using System.Net;
using System.Collections.Specialized;

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // TLS v1.2 only
var client = new WebClient()
{
    Credentials = new NetworkCredential("user", "app_password"),
    BaseAddress = "https://api.bitbucket.org",
};

client.DownloadString(
    "/2.0/repositories/friendly_private_account/repo");     // 403 Forbidden
client.DownloadString(
    "/2.0/repositories/friendly_private_account/repo/src"); // 403 Forbidden
client.UploadValues(
    "/2.0/repositories/friendly_private_account/repo/src",
    new NameValueCollection() {
        { "/bb.txt", "here is\nsome content\n" },
        { "message", "Commit from API, called with C# WebClient" },
    });                                                     // Creates a commit! What!?

这有点奇怪,因为如果您在创建应用程序密码时read启用权限,您会自动获得权限。write

也不是问题DownloadString()。如果 App Password 有webhook权限,则可以读取 Web Hooks。

client.DownloadString(
    "/2.0/repositories/friendly_private_account/repo/hooks");
// {"pagelen": 10, "values": [{ … }]}

有趣的是,curl使用相同的凭据没有任何问题。

$ curl --user "${user}:${app_password}" \
       --url "https://api.bitbucket.org/2.0/repositories/friendly_private_account/repo"
# {"scm": "git", "website": "", "has_wiki": false, … }

运行curlwith--verbose实际上将返回描述您的凭据具有哪些权限以及需要哪些权限的标头。在上面的示例中,它需要repository,而我有repository:write。它没有说我有repository:read,但请求仍然成功。

标签: c#webclientbitbucket-api

解决方案


听起来WebClient只有服务器. Authorization_401 Unauthorized

也许 BitBucket 在某些未经身份验证的端点上以 401 响应,从而引发WebClient重新发送具有身份验证的请求;但在其他人身上返回 403,立即结束请求。

显式添加Authorization标题可以解决问题,尽管有点难看。

using System.Net;
using System.Collections.Specialized;

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;  // TLS v1.2 only
var client = new WebClient()
{
    // Credentials = new NetworkCredential("user", "app_password"), // Take this line out
    BaseAddress = "https://api.bitbucket.org",
};

client.Headers[HttpRequestHeader.Authorization] =
    "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("user:app_password"));

client.DownloadString(
    "/2.0/repositories/friendly_private_account/repo");             // Now it works

推荐阅读