2012-03-23 7 views
0

Twitsharp에서 벗어나 트위터에서 User Streaming을 활용하고 싶습니다. 이렇게하려면 API에 대한 내 요청을 인증하기 위해 자체 oAuth를 작성해야합니다.Oauth, Twitter, 401 Unauthorized

이 작업을 한 번도 해 본적이 없기 때문에 실제로 구현하는 데 어려움이 있습니다. 나는 훌륭한 것을 발견했다. (http://garyshortblog.wordpress.com/2011/02/11/a-twitter-oauth-example-in-c/) 나는 내 자신의 글을 쓰는 방법을 이해하기 위해 노력하고있다. 그러나 나는 심지어 일하는 모범을 얻을 수 없다. 매번 나는 항상 Unauthorized 401을 만난다. 내 토큰 등은 괜찮아요, 그들은 Twitsharp에서 일합니다. Twitsharp 요청과 광산 사이에서 피 들러를 사용하여 비교할 경우 oauth_nonce 및 oauth_signature를 제외하고 정확히 동일합니다.

이것은 내가 지금까지 가지고있는 생각이다.

헤더 :

좋은 - 내 예

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에서 한 달 전부터 업데이트 된 것으로 보입니다 .... – Damo

+0

ahh daniel crenna가 작업을 중단 한 것을 기억합니다. 그는 tweetsharp –

0

Uri.EscapeDataString은 올바른 인코딩 메커니즘을 사용하지 않습니다.

예를 들어, 주제에 다른 게시물을 확인 : 해당 게시물에서

How to get Uri.EscapeDataString to comply with RFC 3986

, 당신은 누군가가 올바른 이스케이프 루틴을 붙여 찾을 수 있습니다. 총으로 줘!

+0

덕분에, 불행히도 그것은 작동하지 않았다. 위 코드가 업데이트되었습니다. – Damo