[英]Oauth, Twitter, 401 Unauthorised
我想脱离Twitsharp并利用Twitter中的User Streaming,为了做到这一点,我需要编写自己的oAuth来根据API验证我的请求。
从来不需要这样做,我真的很难实现它。 我找到了一个很好的示例( http://garyshortblog.wordpress.com/2011/02/11/a-twitter-oauth-example-in-c/ ),试图用来了解如何编写自己的示例。 但是,我什至无法使示例工作。 每次运行它,我总是会遇到401未经授权。 我的令牌等很好,它们在Twitsharp下工作。 如果我使用提琴手在Twitsharp请求和我的之间进行比较,则除了oauth_nonce和oauth_signature之外,它们完全相同。
这是我到目前为止的想法,对此感激不尽。
标头:
良好-与Twitsharp合作
oauth_consumer_key="xxx",
oauth_nonce="eyn5x7hhj06tr8ic",
oauth_signature="aZa5Fg7%2FO%2BbSlO9cYTL7OYLpkAM%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1332540179",
oauth_token="xxx",
oauth_version="1.0"
不好-我的例子
oauth_consumer_key="xxx",
oauth_nonce="NjM0NjgxMzgyNDQ5MTgxMDk5",
oauth_signature="bSryjrvc1t4kMaIpXCGe7uAFmUI%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1332541445",
oauth_token="xxx",
oauth_version="1.0"
码:
/// <summary>
/// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986.
/// </summary>
private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };
/// <summary>
/// Escapes a string according to the URI data string rules given in RFC 3986.
/// </summary>
/// <param name="value">The value to escape.</param>
/// <returns>The escaped value.</returns>
/// <remarks>
/// The <see cref="Uri.EscapeDataString"/> method is <i>supposed</i> to take on
/// RFC 3986 behavior if certain elements are present in a .config file. Even if this
/// actually worked (which in my experiments it <i>doesn't</i>), we can't rely on every
/// host actually having this configuration element present.
/// </remarks>
internal static string EscapeUriDataStringRfc3986(string value)
{
// Start with RFC 2396 escaping by calling the .NET method to do the work.
// This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
// If it does, the escaping we do that follows it will be a no-op since the
// characters we search for to replace can't possibly exist in the string.
StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));
// Upgrade the escaping to RFC 3986, if necessary.
for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++)
{
escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
}
// Return the fully-RFC3986-escaped string.
return escaped.ToString();
}
public static void UserStream()
{
//GS - Get the oAuth params
string status = "statusUpdate112";
string postBody = "status=" +
EscapeUriDataStringRfc3986(status);
string oauth_consumer_key = _consumerKey;
string oauth_nonce = Convert.ToBase64String(
new ASCIIEncoding().GetBytes(
DateTime.Now.Ticks.ToString()));
string oauth_signature_method = "HMAC-SHA1";
string oauth_token =
_accessToken;
TimeSpan ts = DateTime.UtcNow -
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
string oauth_timestamp =
Convert.ToInt64(ts.TotalSeconds).ToString();
string oauth_version = "1.0";
//GS - When building the signature string the params
//must be in alphabetical order. I can't be bothered
//with that, get SortedDictionary to do it's thing
SortedDictionary<string, string> sd =
new SortedDictionary<string, string>();
sd.Add("status", status);
sd.Add("oauth_version", oauth_version);
sd.Add("oauth_consumer_key", oauth_consumer_key);
sd.Add("oauth_nonce", oauth_nonce);
sd.Add("oauth_signature_method", oauth_signature_method);
sd.Add("oauth_timestamp", oauth_timestamp);
sd.Add("oauth_token", oauth_token);
//GS - Build the signature string
string baseString = String.Empty;
baseString += "POST" + "&";
baseString += EscapeUriDataStringRfc3986(
"http://api.twitter.com/1/statuses/update.json")
+ "&";
foreach (KeyValuePair<string, string> entry in sd)
{
baseString += EscapeUriDataStringRfc3986(entry.Key +
"=" + entry.Value + "&");
}
//GS - Remove the trailing ambersand char, remember
//it's been urlEncoded so you have to remove the
//last 3 chars - %26
baseString =
baseString.Substring(0, baseString.Length - 3);
//GS - Build the signing key
string consumerSecret =
_consumerSecret;
string oauth_token_secret =
_accessTokenSecret;
string signingKey =
EscapeUriDataStringRfc3986(consumerSecret) + "&" +
EscapeUriDataStringRfc3986(oauth_token_secret);
//GS - Sign the request
HMACSHA1 hasher = new HMACSHA1(
new ASCIIEncoding().GetBytes(signingKey));
string signatureString = Convert.ToBase64String(
hasher.ComputeHash(
new ASCIIEncoding().GetBytes(baseString)));
//GS - Tell Twitter we don't do the 100 continue thing
ServicePointManager.Expect100Continue = false;
//GS - Instantiate a web request and populate the
//authorization header
HttpWebRequest hwr =
(HttpWebRequest)WebRequest.Create(
@"https://api.twitter.com/1/statuses/update.json");
string authorizationHeaderParams = String.Empty;
authorizationHeaderParams += "OAuth ";
authorizationHeaderParams += "oauth_consumer_key="
+ "\"" + EscapeUriDataStringRfc3986(
oauth_consumer_key) + "\",";
authorizationHeaderParams += "oauth_nonce=" + "\"" +
EscapeUriDataStringRfc3986(oauth_nonce) + "\",";
authorizationHeaderParams += "oauth_signature=" + "\""
+ EscapeUriDataStringRfc3986(signatureString) + "\",";
authorizationHeaderParams +=
"oauth_signature_method=" + "\"" +
EscapeUriDataStringRfc3986(oauth_signature_method) +
"\",";
authorizationHeaderParams += "oauth_timestamp=" + "\"" +
EscapeUriDataStringRfc3986(oauth_timestamp) + "\",";
authorizationHeaderParams += "oauth_token=" + "\"" +
EscapeUriDataStringRfc3986(oauth_token) + "\",";
authorizationHeaderParams += "oauth_version=" + "\"" +
EscapeUriDataStringRfc3986(oauth_version) + "\"";
hwr.Headers.Add(
"Authorization", authorizationHeaderParams);
//added user agent
hwr.UserAgent = "XserT";
//GS - POST off the request
hwr.Method = "POST";
hwr.ContentType = "application/x-www-form-urlencoded";
Stream stream = hwr.GetRequestStream();
byte[] bodyBytes =
new ASCIIEncoding().GetBytes(postBody);
stream.Write(bodyBytes, 0, bodyBytes.Length);
stream.Flush();
stream.Close();
//GS - Allow us a reasonable timeout in case
//Twitter's busy
hwr.Timeout = 3 * 60 * 1000;
try
{
HttpWebResponse rsp = hwr.GetResponse()
as HttpWebResponse;
hwr.KeepAlive = false;
//GS - Do something with the return here...
}
catch (WebException e)
{
//GS - Do some clever error handling here...
}
}
我知道这不能回答您的问题,但是如果您尝试使用linqtotwitter,就可以轻松实现。
有一些在源代码区域有效的示例
我还想添加Tweetsharp可能已贬值。 他在去年年初左右停止了工作。
Uri.EscapeDataString没有使用正确的编码机制。
例如,查看有关此主题的另一篇文章:
如何使Uri.EscapeDataString符合RFC 3986
在那篇文章中,您会发现有人粘贴了正确的逃生例程。 把它当成枪!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.