Twitter OAuth 请求令牌返回未经授权 [英] Twitter OAuth Request Token returning Unauthorized

查看:84
本文介绍了Twitter OAuth 请求令牌返回未经授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 Twitter OAuth 获取请求令牌,但我不断收到 401 Unauthorized,但我不知道为什么.我试图尽可能好地遵循签名的创建,并且在 400 Bad Request 上挣扎了一段时间,但最终破解了代码以获得仅被 401 满足的有效请求.>

我觉得我错过了一些非常简单的东西,但我就是不知道是什么.

这是我正在使用的代码:

using (HttpClient client = new HttpClient()){client.BaseAddress = new Uri("https://api.twitter.com/");client.DefaultRequestHeaders.Accept.Clear();client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);string oauth_nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));string oauth_callback = Uri.EscapeUriString("oob");string oauth_signature_method = "HMAC-SHA1";string oauth_timestamp = Convert.ToInt64(ts.TotalSeconds).ToString();字符串 oauth_consumer_key = OAUTH_KEY;字符串 oauth_version = "1.0";//生成签名string baseString = "POST&";baseString += Uri.EscapeDataString(client.BaseAddress + "oauth/request_token") + "&";//每个 oauth 值按字母顺序排序baseString += Uri.EscapeDataString("oauth_callback=" + oauth_callback + "&");baseString += Uri.EscapeDataString("oauth_consumer_key=" + oauth_consumer_key + "&");baseString += Uri.EscapeDataString("oauth_nonce=" + oauth_nonce + "&");baseString += Uri.EscapeDataString("oauth_signature_method=" + oauth_signature_method + "&");baseString += Uri.EscapeDataString("oauth_timestamp=" + oauth_timestamp + "&");baseString += Uri.EscapeDataString("oauth_version=" + oauth_version + "&");字符串signingKey = Uri.EscapeDataString(OAUTH_SECRET) + "&";HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(signingKey));string oauth_signature = Convert.ToBase64String(hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));client.DefaultRequestHeaders.Add("授权", "OAuth " +"oauth_nonce=\"" + oauth_nonce + "\"," +"oauth_callback=\"" + oauth_callback + "\"," +"oauth_signature_method=\"" + oauth_signature_method + "\"," +"oauth_timestamp=\"" + oauth_timestamp + "\"," +"oauth_consumer_key=\"" + oauth_consumer_key + "\"," +"oauth_signature=\"" + Uri.EscapeDataString(oauth_signature) + "\"," +"oauth_version=\"" + oauth_version + "\"");HttpResponseMessage response = await client.PostAsJsonAsync("oauth/request_token", "");var responseString = await response.Content.ReadAsStringAsync();}

我使用的是 .Net 4.5,所以 Uri.EscapeDataString() 应该给出正确的百分比编码字符串.

编辑

我注意到 oauth_nonce 值有时包含非字母数字字符,因此我将变量计算更改为以下内容:

string nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));string oauth_nonce = new string(nonce.Where(c => Char.IsLetter(c) || Char.IsDigit(c)).ToArray());

不幸的是,这没有帮助.

我还为 Authorization 标头中的所有值尝试了 Uri.EscapeUriData(),并在每个逗号后添加了一个空格(作为文档Twitter 是这么说的),但这也无济于事.

解决方案

我从头开始并尝试了一种稍微不同的方法,但它应该产生相同的结果.然而,它没有,而是按预期工作!

如果有人能指出此工作代码与原始问题中的代码之间的实际区别,我将非常感激,因为在我看来它们产生了相同的结果.

using (HttpClient client = new HttpClient()){client.BaseAddress = new Uri("https://api.twitter.com/");client.DefaultRequestHeaders.Accept.Clear();client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));TimeSpan 时间戳 = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);string nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));字典<字符串,字符串>oauth = 新字典<字符串,字符串>{["oauth_nonce"] = new string(nonce.Where(c => char.IsLetter(c) || char.IsDigit(c)).ToArray()),["oauth_callback"] = "http://my.callback.url",["oauth_signature_method"] = "HMAC-SHA1",["oauth_timestamp"] = Convert.ToInt64(timestamp.TotalSeconds).ToString(),[oauth_consumer_key"] = OAUTH_KEY,["oauth_version"] = "1.0"};string[] parameterCollectionValues = oauth.Select(parameter =>Uri.EscapeDataString(parameter.Key) + "=" +Uri.EscapeDataString(parameter.Value)).OrderBy(kv => kv).ToArray();string parameterCollection = string.Join("&", parameterCollectionValues);string baseString = "POST";baseString += "&";baseString += Uri.EscapeDataString(client.BaseAddress + "oauth/request_token");baseString += "&";baseString += Uri.EscapeDataString(parameterCollection);字符串signingKey = Uri.EscapeDataString(OAUTH_SECRET);签名密钥 += "&";HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(signingKey));oauth["oauth_signature"] = Convert.ToBase64String(hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));string headerString = "OAuth ";string[] headerStringValues = oauth.Select(parameter =>Uri.EscapeDataString(parameter.Key) + "=" + "\"" +Uri.EscapeDataString(parameter.Value) + "\"").ToArray();headerString += string.Join(", ", headerStringValues);client.DefaultRequestHeaders.Add("Authorization", headerString);HttpResponseMessage response = await client.PostAsJsonAsync("oauth/request_token", "");var responseString = await response.Content.ReadAsStringAsync();}

I'm trying to get a request token from Twitter OAuth, but I keep getting 401 Unauthorized, but I have no idea why. I have tried to follow the signature creation as good as I can and was struggling with 400 Bad Request for a while but finally cracked the code to get a valid request only to be met by the 401.

I feel like I'm missing something really simple but I just can't find out what.

Here's the code I'm using:

using (HttpClient client = new HttpClient())
{
    client.BaseAddress = new Uri("https://api.twitter.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

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

    string oauth_nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
    string oauth_callback = Uri.EscapeUriString("oob");
    string oauth_signature_method = "HMAC-SHA1";
    string oauth_timestamp = Convert.ToInt64(ts.TotalSeconds).ToString();
    string oauth_consumer_key = OAUTH_KEY;
    string oauth_version = "1.0";

    // Generate signature
    string baseString = "POST&";
    baseString += Uri.EscapeDataString(client.BaseAddress + "oauth/request_token") + "&";
    // Each oauth value sorted alphabetically
    baseString += Uri.EscapeDataString("oauth_callback=" + oauth_callback + "&");
    baseString += Uri.EscapeDataString("oauth_consumer_key=" + oauth_consumer_key + "&");
    baseString += Uri.EscapeDataString("oauth_nonce=" + oauth_nonce + "&");
    baseString += Uri.EscapeDataString("oauth_signature_method=" + oauth_signature_method + "&");
    baseString += Uri.EscapeDataString("oauth_timestamp=" + oauth_timestamp + "&");
    baseString += Uri.EscapeDataString("oauth_version=" + oauth_version + "&");

    string signingKey = Uri.EscapeDataString(OAUTH_SECRET) + "&";
    HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(signingKey));
    string oauth_signature = Convert.ToBase64String(hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));

    client.DefaultRequestHeaders.Add("Authorization", "OAuth " +
        "oauth_nonce=\"" + oauth_nonce + "\"," +
        "oauth_callback=\"" + oauth_callback + "\"," +
        "oauth_signature_method=\"" + oauth_signature_method + "\"," +
        "oauth_timestamp=\"" + oauth_timestamp + "\"," +
        "oauth_consumer_key=\"" + oauth_consumer_key + "\"," +
        "oauth_signature=\"" + Uri.EscapeDataString(oauth_signature) + "\"," +
        "oauth_version=\"" + oauth_version + "\""
    );

    HttpResponseMessage response = await client.PostAsJsonAsync("oauth/request_token", "");
    var responseString = await response.Content.ReadAsStringAsync();
}

I'm using .Net 4.5 so the Uri.EscapeDataString() should give the correct percent encoded string.

EDIT

I noticed that the oauth_nonce value sometimes included non-alphanumeric characters so I changed the variable calculation to the following:

string nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
string oauth_nonce = new string(nonce.Where(c => Char.IsLetter(c) || Char.IsDigit(c)).ToArray());

This unfortunately didn't help.

I've also tried Uri.EscapeUriData() for all the values in the Authorization header, as well as adding a space after each comma (as the documentation on Twitter says so), but that didn't help either.

解决方案

I started from scratch and tried a slightly different approach, but it should've yielded the same result. However, it didn't and instead works as intended!

If anybody can point of the practical difference between this working code and the code in the original question, I would really appreciate it, because to my eyes they produce identical results.

using (HttpClient client = new HttpClient())
{
    client.BaseAddress = new Uri("https://api.twitter.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    TimeSpan timestamp = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    string nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));

    Dictionary<string, string> oauth = new Dictionary<string, string>
    {
        ["oauth_nonce"] = new string(nonce.Where(c => char.IsLetter(c) || char.IsDigit(c)).ToArray()),
        ["oauth_callback"] = "http://my.callback.url",
        ["oauth_signature_method"] = "HMAC-SHA1",
        ["oauth_timestamp"] = Convert.ToInt64(timestamp.TotalSeconds).ToString(),
        ["oauth_consumer_key"] = OAUTH_KEY,
        ["oauth_version"] = "1.0"
    };

    string[] parameterCollectionValues = oauth.Select(parameter =>
            Uri.EscapeDataString(parameter.Key) + "=" +
            Uri.EscapeDataString(parameter.Value))
        .OrderBy(kv => kv)
        .ToArray();
    string parameterCollection = string.Join("&", parameterCollectionValues);

    string baseString = "POST";
    baseString += "&";
    baseString += Uri.EscapeDataString(client.BaseAddress + "oauth/request_token");
    baseString += "&";
    baseString += Uri.EscapeDataString(parameterCollection);

    string signingKey = Uri.EscapeDataString(OAUTH_SECRET);
    signingKey += "&";
    HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(signingKey));
    oauth["oauth_signature"] = Convert.ToBase64String(hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));

    string headerString = "OAuth ";
    string[] headerStringValues = oauth.Select(parameter =>
            Uri.EscapeDataString(parameter.Key) + "=" + "\"" +
            Uri.EscapeDataString(parameter.Value) + "\"")
        .ToArray();
    headerString += string.Join(", ", headerStringValues);

    client.DefaultRequestHeaders.Add("Authorization", headerString);

    HttpResponseMessage response = await client.PostAsJsonAsync("oauth/request_token", "");
    var responseString = await response.Content.ReadAsStringAsync();
}

这篇关于Twitter OAuth 请求令牌返回未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆