我有一个 Windows 8 和一个 Windows Phone 8 应用程序,用作社交媒体仪表板,它使用 twitter 搜索 api 获取推文。这最初是使用 Twitter API 1 实现的,并且不需要身份验证,因此由于它不需要任何额外的 3rd 方库,因此它被放置在解决方案的 PCL 部分中。出于同样的原因,我希望在没有任何库的情况下完成使用 1.1 API 的更新。我在 Twitter 开发社区和 codeproject 上在线找到了各种示例,并对其进行了修改以与 PCL 一起使用。
以下是尝试搜索 twitter 的部分代码:
private static async Task<string> doTheTwitterMagic(string query)
{
var oauth_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var oauth_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var oauth_consumer_key = "XXXXXXXXXXXXXXXXX";
var oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var resource_url = "https://api.twitter.com/1.1/search/tweets.json";
// oauth implementation details
var oauth_version = "1.0";
var oauth_signature_method = "HMAC-SHA1";
Encoding ascii = new AsciiEncoding();
// unique request details
var oauth_nonce = Convert.ToBase64String(
ascii.GetBytes(DateTime.Now.Ticks.ToString()));
var timeSpan = DateTime.UtcNow
- new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
// create oauth signature
var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
"&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&q={6}";
var baseString = string.Format(baseFormat,
oauth_consumer_key,
oauth_nonce,
oauth_signature_method,
oauth_timestamp,
oauth_token,
oauth_version,
Uri.EscapeDataString(query)
);
baseString = string.Concat("GET&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString));
var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
"&", Uri.EscapeDataString(oauth_token_secret));
string oauth_signature;
using (HMACSHA1 hasher = new HMACSHA1(ascii.GetBytes(compositeKey)))
{
oauth_signature = Convert.ToBase64String(
hasher.ComputeHash(ascii.GetBytes(baseString)));
}
// create the request header
var headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
"oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
"oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
"oauth_version=\"{6}\"";
var authHeader = string.Format(headerFormat,
Uri.EscapeDataString(oauth_nonce),
Uri.EscapeDataString(oauth_signature_method),
Uri.EscapeDataString(oauth_timestamp),
Uri.EscapeDataString(oauth_consumer_key),
Uri.EscapeDataString(oauth_token),
Uri.EscapeDataString(oauth_signature),
Uri.EscapeDataString(oauth_version)
);
return authHeader;
}
public static async Task<List<TwitterObject>> GetTweetsFromSearchAsync(string query)
{
try
{
string authHeader = await doTheTwitterMagic(query);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://api.twitter.com/1.1/search/tweets.json?q="+query);
webRequest.Headers[HttpRequestHeader.Authorization] = authHeader;
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "GET";
var webResponse = await webRequest.GetResponseAsync();
var json = string.Empty;
using (var reader = new StreamReader(webResponse.GetResponseStream()))
json = await reader.ReadToEndAsync();
var jsonObject = JObject.Parse(json);
var results = new List<TwitterObject>();
foreach (JToken token in jsonObject["results"])
results.Add(token.ToObject<TwitterObject>());
return results;
}
catch (Exception e) { throw e; }
}
注意:AsciiEncoding 是 ASCIIEncoding 的自定义实现,因为它目前在 PCL 中不可用。
现在我尝试了标准调试,我看到的第一件事是 Twitter OAuth 工具,这是 OAuth 工具与我的应用程序的结果
OAuth 工具签名基本字符串:
GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3D3c30afb0c2a391d3b4e4ba3da057c2ca%26oauth_
signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1371309728%26oauth_token%3D16702
294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3Dcsmcr
我的应用签名基本字符串:
GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3DNjM1MDY5MTA1MzA2MTU1NTgz%26oauth_signatur
e_method%3DHMAC-SHA1%26oauth_timestamp%3D1371310131%26oauth_token%3D16702294-3WNj
fZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3D%2540csmcr
乍一看,唯一的区别是随机数,但这不应该是一个问题 编辑说明:我刚刚注意到,在 OAuth 工具的末尾我有 % 26q%3Dcsmcr 和我的应用程序生成 %26q%3D%2540csmcr 但这只是因为我忘记在 OAuth 工具的查询中包含一个字符。添加字符后,字符串最后变得相同。
OAuth 工具授权标头:
Authorization: OAuth oauth_consumer_key="ywWuYGASkHMsHsC22Vpw",
oauth_nonce="3c30afb0c2a391d3b4e4ba3da057c2ca",
oauth_signature="tofmGp6qaAUAPZnQHhQlVFWN40M%3D",
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309728",
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM",
oauth_version="1.0"
我的应用授权标头:
Authorization: OAuth oauth_nonce="NjM1MDY5MDk5NTY5Nzc1MTc5",
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309557",
oauth_consumer_key="ywWuYGASkHMsHsC22Vpw",
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM",
oauth_signature="q1544JDPUXdUwY3fmEk3mtGGEwk%3D", oauth_version="1.0"
除了随机数和签名之外,也没有太大区别。键值对的顺序似乎没有什么区别,因为我重新排列它们进行了测试,但仍然有同样的问题。
所以我遇到的问题是,当函数运行时,我总是得到 401 Unauthorized 错误
{"errors":[{"message":"Could not authenticate you","code":32}]}
错误。
任何指针将不胜感激。
编辑:对此进行了更多测试,获取了由 Twitter OAuth 工具生成的 nonce 和时间戳,并将它们硬编码到我的应用程序中,以检查签名是否正确,结果证明是,我得到了相同的 oauth_signature OAuth 工具中的一个。这意味着 Auth 标头也应该完全没问题。所以我想问题出在我的请求中。