Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么BitBucket OAuth请求“令牌API总是返回400”;无法验证OAuth请求;?_C#_Api_Oauth_Bitbucket Api - Fatal编程技术网

C# 为什么BitBucket OAuth请求“令牌API总是返回400”;无法验证OAuth请求;?

C# 为什么BitBucket OAuth请求“令牌API总是返回400”;无法验证OAuth请求;?,c#,api,oauth,bitbucket-api,C#,Api,Oauth,Bitbucket Api,为了让BitBucket OAuth API正常工作,我花了整整一周的时间在办公桌上敲打脑袋,但我甚至连一个拯救自己生命的请求令牌都拿不到。我在这里编写的代码适用于LinkedIn,但BitBucket总是返回HTTP状态代码400,并显示一条非常详细和有用的消息:“无法验证OAuth请求” 这是一个简单的代码(50行,不能缩短),这样做是因为我需要手动实现OAuth,否则我不会在这里询问并使用其他外部库,但由于公司的要求,我不允许在这个项目中使用外部libs。不过我不知道有什么不对,1.0a并

为了让BitBucket OAuth API正常工作,我花了整整一周的时间在办公桌上敲打脑袋,但我甚至连一个拯救自己生命的请求令牌都拿不到。我在这里编写的代码适用于LinkedIn,但BitBucket总是返回HTTP状态代码400,并显示一条非常详细和有用的消息:“无法验证OAuth请求”

这是一个简单的代码(50行,不能缩短),这样做是因为我需要手动实现OAuth,否则我不会在这里询问并使用其他外部库,但由于公司的要求,我不允许在这个项目中使用外部libs。不过我不知道有什么不对,1.0a并不是那么难,而且获取请求令牌应该不会花这么长时间。有什么不对劲吗

我还检查了我的时间戳,结果很好,w32tm.exe对pool.ntp.org返回的时间是+30或其他值。我还尝试在UtcNow时间戳中添加和删除30分钟,但没有成功,但我的时钟已正确同步(与本地时间和正确的GMT值(GMT-4:30))因此毫无意义

可能是因为我在公司防火墙(Forefront)后面吗?但是,为什么LinkedIn的API调用有效,而BitBucket不行呢?我还阅读了大量的文件,如OAuth圣经、RFC、官方文件等,当然在提问前对其进行了广泛的搜索,并在点击“发布您的问题”按钮之前查看了“类似问题”面板中显示的所有链接

下面是简单的代码(C#):

编辑:这是一个小提琴手和浏览器请求捕获:

提前谢谢

编辑2:我使用n0741337建议提供的类进行了一个新的测试,但是,该类不符合1.0A规范,该规范要求回调方法(至少Bitbucket好心地说需要这样的参数)所以我不得不修改它,使其在基本签名字符串中包含回调参数(原始格式,无编码)。尽管结果相同(我想如果我显示我的密钥并不重要,因为你无论如何都看不到我的密钥),这里有一个捕获:

这是签名的基本字符串:

GET&https%3A%2F%2Fbitbucket.org%2Fapi%2F1.0%2Foauth%2Frequest_token&oauth_callback%3Dhttp%3A%2F%2Flocalhost%3A4000%2F%26oauth_consumer_key%3Dkey%26oauth_nonce%3D8231861%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1423671576%26oauth_version%3D1.0
另外,要怀疑我的代码,还可以使用我发现的已经适应Twitter的人(虽然Twitter在我的工作场所被屏蔽,所以我无法测试),但结果是一样的

下面是我使用这些类编写的新代码:

using System;
using System.Net;
using System.Security.Cryptography;
using OAuth;

namespace OAuthTest1
{
    public class oauth2
    {

        public static void Run()
        {
            OAuthBase a = new OAuthBase();
            String nonce = a.GenerateNonce();
            String ts = a.GenerateTimeStamp();
            String key = "key";
            String secret = "secret";
            String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

            String normalizedUrl, normalizedArgs;
            String sigBase = a.GenerateSignatureBase(
                new Uri(requestUrl),
                key,
                null,
                secret,
                "http://localhost:4000/",
                "GET",
                ts,
                nonce,
                "HMAC-SHA1",
                out normalizedUrl,
                out normalizedArgs
            );
            String sig = a.GenerateSignatureUsingHash(sigBase, new HMACSHA1());

            String GETArgs = String.Empty;
            GETArgs += "oauth_consumer_key=" + key;
            GETArgs += "&oauth_nonce=" + nonce;
            GETArgs += "&oauth_signature_method=HMAC-SHA1";
            GETArgs += "&oauth_timestamp=" + ts;
            GETArgs += "&oauth_version=1.0";
            GETArgs += "&oauth_callback=" + a.UrlEncode("http://localhost:4000/");
            GETArgs += "&oauth_signature=" + sig;

            WebClient w = new WebClient();
            Console.WriteLine(w.DownloadString(requestUrl + "?" + GETArgs));

            Console.ReadKey();
        }

    }
}
编辑2的问题:是否有人知道有一个应用程序通过此方法连接到Bitbucket的服务,这样我就可以运行Fiddler并查看它发送了什么?如果我能看到一些输出,我至少可以复制流程:/I我已经尝试过使用SourceTree,但效果不太好

编辑3:根据AZ.的建议,我用这个更改了时间戳生成代码,但它无论如何都不起作用:(.时间戳值看起来不错,但我的时间戳和服务器的时间戳之间只有5秒的细微差别:

TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
String timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString();
另外,我注意到签名中包含一个“+”,它应该被编码为%20,当我在编辑问题后注意到它时,我就这么做了,但它也不起作用,仅供参考


不确定这是否是原因,但这条线很臭:

TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);

您正在从UTC中减去DateTimeKind。未指定的日期。我没有可用的环境来测试这一点,但将1970年的日期构造为UTC可能会有所帮助

我怀疑您的问题在于您正在本地开发服务器上调试此项,并且您作为回调URL发送的此URL对位于Inter服务器上的客户端无效净:

GETArgs += "&oauth_callback=" + a.UrlEncode("http://localhost:4000/");
我还没有读过BitBucket的文档,但是GoogleOAuth的实现方式是,您需要有一个可公开访问的URL,以便将回调消息发送到该URL,以便握手能够正常工作


您的浏览器不会回调此URL,它是从他们的服务器调用的,因此它必须可以通过Internet访问。

您的程序有两个问题:

  • 您没有发送
    内容类型:application/x-www-form-urlencoded
    标题,这会使文章正文无法理解(通常建议使用授权请求标题)
  • 您没有正确创建签名基字符串。签名基字符串是OAuth 1.0中最微妙的部分,因为客户端和服务器必须独立地生成完全相同的字节序列。使用
    OAuth\u回调
    时,参数的顺序错误()
以下是使程序正常工作的修补程序:

--- Program.cs  2015-02-23 23:13:03.000000000 -0800
+++ Program3.cs 2015-02-23 23:20:37.000000000 -0800
@@ -15,11 +15,12 @@
             String secret = "SECRET";
             String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

-            string sigBaseStringParams = "oauth_consumer_key=" + key;
+            string sigBaseStringParams = "";
+            sigBaseStringParams += "oauth_callback=http%3A%2F%2Flocal%3Fdump";
+            sigBaseStringParams += "&" + "oauth_consumer_key=" + key;
             sigBaseStringParams += "&" + "oauth_nonce=" + GetNonce();
             sigBaseStringParams += "&" + "oauth_signature_method=" + "HMAC-SHA1";
             sigBaseStringParams += "&" + "oauth_timestamp=" + GetTimeStamp();
-            sigBaseStringParams += "&" + "oauth_callback=http%3A%2F%2Flocal%3Fdump";
             sigBaseStringParams += "&" + "oauth_version=1.0";
             string sigBaseString = "POST&";
             sigBaseString += Uri.EscapeDataString(requestUrl) + "&" + Uri.EscapeDataString(sigBaseStringParams);
@@ -44,6 +45,7 @@
         public static String PostData(string url, string postData)
         {
             WebClient w = new WebClient();
+            w.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
             return w.UploadString(url, postData);
         }

这真的是一个“获取请求令牌失败(状态:400数据:无法验证OAuth请求。)错误吗?运行fiddler,在浏览器中重试,您应该会收到更详细的消息。是的!我添加了一个屏幕截图,以便您可以看到确切的问题:)1。bitbucket是否接受回调。。。2.回调是否需要REST端点?我相信它很可能需要一个有效的公共url。。。不是谷歌:Dbtw我看到一些人说bitbucket必须在系统时钟的5分钟之内。。。你从哪里得到30分钟的时间?你能发布构建后的
sigBaseString
的样子吗?另外-推荐的代码对您有用吗?虽然您的建议非常正确,因为原始代码(包括我的代码和oauth提供的代码)没有使用完整的UTC日期,但我将时间戳生成代码更改为:
TimeSpan ts=DateTime.UtcNow-new DateTime(1970,1,1,0,0,0,0,DateTimeKind.UTC);字符串时间戳=Convert.ToInt64(ts.TotalSeconds.ToString()但结果仍然相同。我已经用我正在生成的数据的新屏幕截图更新了OP,并将其与Bitbucket的服务器进行了比较。
--- Program.cs  2015-02-23 23:13:03.000000000 -0800
+++ Program3.cs 2015-02-23 23:20:37.000000000 -0800
@@ -15,11 +15,12 @@
             String secret = "SECRET";
             String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

-            string sigBaseStringParams = "oauth_consumer_key=" + key;
+            string sigBaseStringParams = "";
+            sigBaseStringParams += "oauth_callback=http%3A%2F%2Flocal%3Fdump";
+            sigBaseStringParams += "&" + "oauth_consumer_key=" + key;
             sigBaseStringParams += "&" + "oauth_nonce=" + GetNonce();
             sigBaseStringParams += "&" + "oauth_signature_method=" + "HMAC-SHA1";
             sigBaseStringParams += "&" + "oauth_timestamp=" + GetTimeStamp();
-            sigBaseStringParams += "&" + "oauth_callback=http%3A%2F%2Flocal%3Fdump";
             sigBaseStringParams += "&" + "oauth_version=1.0";
             string sigBaseString = "POST&";
             sigBaseString += Uri.EscapeDataString(requestUrl) + "&" + Uri.EscapeDataString(sigBaseStringParams);
@@ -44,6 +45,7 @@
         public static String PostData(string url, string postData)
         {
             WebClient w = new WebClient();
+            w.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
             return w.UploadString(url, postData);
         }