我正在使用使用OAuth 1.0的API。除了使用标准方法之外,API的网站上没有文档。我在推特网站https://dev.twitter.com/oauth/overview/creating-signatures上关注了指南。
对我来说似乎一切都很好,但我不断收到一条消息,告诉我签名无效。我开始在github上找到一个类,我收到了签名错误。这个类非常复杂,所以我编写了自己的简单类(使用C#)。我有一个构造函数,可以正确设置此处使用的所有值。我100%确定没有丢失数据,问题必须与签名/请求的生成方式有关,但据我所知,一切都设置正确。输出标题看起来正确,并填充了所有内容。有什么想法是错的吗?
public string GenerateHeaderString(string url, string method)
{
string auth = "OAuth oauth_consumer_key=\"" + ConsumerKey + "\",oauth_token=\"" + HttpUtility.UrlEncode(Token) + "\",oauth_signature_method=\"" + SignatureMethod
+ "\",oauth_timestamp=\"" + Timestamp + "\",oauth_nonce=\"" + Nonce + "\",oauth_version=\"" + Version + "\",oauth_signature=\"" + GenerateSignature(url, method) + "\"";
return auth;
}
public string GenerateSignature(string url, string method)
{
string signature = method + "&" + HttpUtility.UrlEncode(url) + "&" + HttpUtility.UrlEncode("oauth_consumer_key=" + ConsumerKey
+ "&oauth_nonce=" + Nonce + "&oauth_signature_method=" + SignatureMethod + "&oauth_timestamp="
+ Timestamp + "&oauth_token=" + Token + "&oauth_version=" + Version);
switch(SignatureMethod)
{
case "HMAC-SHA1":
string keystring = string.Format("{0}&{1}", HttpUtility.UrlEncode(this.ConsumerSecret),HttpUtility.UrlEncode(this.TokenSecret));
var hmacsha1 = new HMACSHA1
{
Key = System.Text.Encoding.ASCII.GetBytes(keystring)
};
byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(signature);
byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
this.Signature = HttpUtility.UrlEncode(Convert.ToBase64String(hashBytes));
break;
}
return this.Signature;
}
答案 0 :(得分:0)
我认为问题是你需要在哈希之前对签名进行URLEncode编码。前两个&符号不会被编码,但其他一切都会编码。这是我使用的一些代码。我遇到的唯一问题是查询字符串在值中包含空格。
var signatureType = string.Empty;
switch (((OAuth1)webRequestDetails.Authentication).SignatureMethod)
{
case SignatureMethod.HMACSHA1:
{
signatureType = "HMAC-SHA1";
break;
}
case SignatureMethod.HMACSHA256:
{
signatureType = "HMAC-SHA256";
break;
}
case SignatureMethod.PLAINTEXT:
{
signatureType = "PLAINTEXT";
break;
}
}
var baseUrl = webRequestDetails.Url;
var queryStrings = new List<string>();
var queryStartIndex = baseUrl.IndexOf("?", StringComparison.Ordinal);
if (queryStartIndex != -1)
{
queryStrings = baseUrl.Substring(queryStartIndex + 1, baseUrl.Length - queryStartIndex - 1).Split('&').ToList();
baseUrl = baseUrl.Substring(0, queryStartIndex);
}
//string builder will be used to append all the key value pairs
var stringBuilder = new StringBuilder();
stringBuilder.Append(httpMethod.Method.ToUpper() + "&");
stringBuilder.Append(Uri.EscapeDataString(baseUrl));
stringBuilder.Append("&");
//the key value pairs have to be sorted by encoded key
var dictionary = new SortedDictionary<string, string>
{
{"oauth_version", "1.0"},
{"oauth_consumer_key", ((OAuth1) webRequestDetails.Authentication).ConsumerKey},
{"oauth_nonce", ((OAuth1) webRequestDetails.Authentication).Nonce},
{"oauth_signature_method", signatureType},
{"oauth_timestamp", ((OAuth1) webRequestDetails.Authentication).TimeStamp},
{"oauth_token", ((OAuth1) webRequestDetails.Authentication).Token}
};
//merge in the querystrings
foreach (var queryString in queryStrings)
{
var queryStringParts = queryString.Split('=');
dictionary.Add(queryStringParts[0], queryStringParts[1]);
}
foreach (var keyValuePair in dictionary)
{
//append a = between the key and the value and a & after the value
stringBuilder.Append(Uri.EscapeDataString($"{keyValuePair.Key}={keyValuePair.Value}&"));
}
var signatureBaseString = stringBuilder.ToString().Substring(0, stringBuilder.Length - 3);
//generation the signature key the hash will use
var signatureKey =
Uri.EscapeDataString(((OAuth1) webRequestDetails.Authentication).ConsumerSecret) + "&" +
Uri.EscapeDataString(((OAuth1) webRequestDetails.Authentication).TokenSecret);
var hmacsha1 = new HMACSHA1(
new ASCIIEncoding().GetBytes(signatureKey));
//hash the values
var signatureString = Convert.ToBase64String(
hmacsha1.ComputeHash(
new ASCIIEncoding().GetBytes(signatureBaseString)));
return signatureString;