2012-03-23 29 views
0

私はTwitsharpから離れ、Twitterでユーザーストリーミングを利用したいと思っています。これを行うには、APIに対する自分のリクエストを認証するために自分のoAuthを書く必要があります。Oauth、Twitter、401 Unauthorized

これを行う必要は決してありませんでしたが、私は実際にそれを実装するのに苦労しています。私は自分自身を書く方法を理解するために使っている優れた例(http://garyshortblog.wordpress.com/2011/02/11/a-twitter-oauth-example-in-c/)を見つけました。しかし、私は仕事の例を得ることさえできません。毎回私は401 Unauthorizedに遭遇します。私のトークンなどはうまく、Twitsharpの下で働いています。私がTwitsharpリクエストと私の間でFiddlerを使って比較すると、oauth_nonceとoauth_signatureを除いて全く同じです。

これは私が今までに持っていたものです。

ヘッダ:

GOOD - 私の例

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" 

コード - 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での作業:

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



     } 
+0

Twitsharpのコンシューマーキーではなく、あなた自身のアプリケーションを使用していることを願っていますか? –

+0

?なぜ私はTwitsharpのコンシューマーキーを使用していますか? – Damo

答えて

0

私はあなたの質問に答えていないが、あなたがlinqtotwitterを試してみればそれは簡単に行うことができます知っている。

は私もTweetsharpはおそらく減価償却される追加したいソースエリアで働く例があります。彼は昨年ほど早く作業をやめた。

+0

そのため、OAUTHとAPIをよりよく理解したいのです。しかし、NuGetには、1ヶ月前からのアップデートがあるようです.... – Damo

+0

ダニエル・クルナはそれに取り組むのをやめました。彼はつぶやきを –

0

Uri.EscapeDataStringは、正しいエンコードメカニズムを使用していません。

例えば、被写体にこの他のポストをチェックアウト:そのポストで

How to get Uri.EscapeDataString to comply with RFC 3986

、誰かが正しいエスケープルーチンを貼り付けができます。ショットとして与えてください!

+0

ありがとう、残念ながらそれは動作しませんでした。コードは上記で更新されました。 – Damo

関連する問題