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

时间:2019-02-14 19:44:53

标签: c# webclient 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()也不是问题。如果应用密码具有webhook权限,则可以阅读Web挂钩。

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一起运行实际上会返回标头,这些标头描述了您的凭据具有所需的权限。在上面的示例中,它需要repository,而我有repository:write。并不是说我有repository:read,但是请求仍然成功。

1 个答案:

答案 0 :(得分:0)

听起来WebClient仅发送Authorization标头when the server responds with a 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