C# 可以写入但不能读取存储库的 BitBucket API

C# can write but not read BitBucket API for repositories

我正在尝试使用 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!?

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

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, … }

运行 curl--verbose 实际上 return headers 描述了您的凭据具有哪些权限 需要哪些权限。在上面的示例中,它需要 repository,而我有 repository:write。它并没有说我有repository:read,但是请求还是成功了。

听起来 WebClient 只发送 Authorization header when the server responds with a 401 Unauthorized.

也许 BitBucket 在一些未经身份验证的端点上以 401 响应,促使 WebClient 重新发送带有身份验证的请求;但是 returns 其他人的 403,立即结束请求。

明确添加 Authorization header 可以解决问题,尽管有点难看。

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