简体   繁体   English

Oauth,Twitter,401未经授权

[英]Oauth, Twitter, 401 Unauthorised

I want to break away from Twitsharp and utilise the User Streaming in twitter, in order to do this I need to write my own oAuth for authenticating my requests against the API. 我想脱离Twitsharp并利用Twitter中的User Streaming,为了做到这一点,我需要编写自己的oAuth来根据API验证我的请求。

Having never had to do this I'm really struggling to implement it. 从来不需要这样做,我真的很难实现它。 I found an excellent example ( http://garyshortblog.wordpress.com/2011/02/11/a-twitter-oauth-example-in-c/ ) which I'm attempting to use to understand how to write my own. 我找到了一个很好的示例( http://garyshortblog.wordpress.com/2011/02/11/a-twitter-oauth-example-in-c/ ),试图用来了解如何编写自己的示例。 However I can't even get the example to work. 但是,我什至无法使示例工作。 Each time run it I always encounter 401 Unauthorised. 每次运行它,我总是会遇到401未经授权。 My tokens etc. are fine, they work under Twitsharp. 我的令牌等很好,它们在Twitsharp下工作。 If I make a comparison using fiddler between a Twitsharp request and mine, they are exactly the same with the exception of the oauth_nonce and oauth_signature. 如果我使用提琴手在Twitsharp请求和我的之间进行比较,则除了oauth_nonce和oauth_signature之外,它们完全相同。

This is what I have so far, thoughts appreciated. 这是我到目前为止的想法,对此感激不尽。

Headers: 标头:

GOOD - Working with Twitsharp 良好-与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"

BAD - My Example 不好-我的例子

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"

Code: 码:

     /// <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...
            }



        }

i know this doesnt answer your question but if you try linqtotwitter you can do it easy. 我知道这不能回答您的问题,但是如果您尝试使用linqtotwitter,就可以轻松实现。

There are examples that work in the source area 有一些在源代码区域有效的示例

I also want to add Tweetsharp is probably depreciated. 我还想添加Tweetsharp可能已贬值。 he stopped working on it early last year or so. 他在去年年初左右停止了工作。

The Uri.EscapeDataString does not use correct encoding mechanism. Uri.EscapeDataString没有使用正确的编码机制。

For instance, check this other post out on the subject: 例如,查看有关此主题的另一篇文章:

How to get Uri.EscapeDataString to comply with RFC 3986 如何使Uri.EscapeDataString符合RFC 3986

In that post, you will find someone pasted a correct escape routine. 在那篇文章中,您会发现有人粘贴了正确的逃生例程。 Give it as shot! 把它当成枪!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM