2017-02-25 1 views
0

J'essaie d'utiliser OAuth utilisateur unique pour Twitter pour lancer une recherche sur l'API Twitter. J'ai découvert cette bibliothèque utile que me laisse le faire: https://gist.github.com/EelcoKoster/326aa7d1b1338806b058ddcc404622b6Twitter OAuth utilisateur unique échoue lorsque la demande a un caractère deux-points

(basé sur l'œuvre originale ici: https://blog.dantup.com/2016/07/simplest-csharp-code-to-post-a-tweet-using-oauth)

Cependant, alors que je peux envoyer des requêtes avec cette bibliothèque et obtenir des résultats pour les recherches en texte clair, il selfs lorsque j'essaie d'interroger un emplacement, par exemple: geocode: 26.201461, -98.237987,0.25mi

Après quelques tests, il semble que ce soit le caractère deux-points qui cause le problème. Le retirer de la requête me donne des résultats (vide car il n'y a pas une telle chaîne dans twitter, mais réussie); l'ajouter en arrière donne l'erreur: Impossible de vous authentifier.

J'ai essayé de jouer avec l'encodage des paramètres mais je n'arrive à rien.

Je suis sûr que cela peut être fait, comme la console API semble utiliser cette même autorisation: https://dev.twitter.com/rest/tools/console

et je peux faire une telle recherche, il doit être quelque chose de mal avec ma signature.

Ceci est le code correspondant (je l'ai codé en dur ma requête pour le test):

public Task<string> Search(string search) 
    { 
     // search = Uri.EscapeDataString(search); 
     return SendRequest("search/tweets.json?q=geocode:26.201461,-98.237987,0.25mi", HttpMethod.GET, new Dictionary<string, string>()); 
    } 

    Task<string> SendRequest(string url, HttpMethod httpMethod, Dictionary<string, string> data) 
    { 
     var fullUrl = TwitterApiBaseUrl + url; 
     Random rand = new Random(); 

     // Timestamps are in seconds since 1/1/1970. 
     var timestamp = (int) ((DateTime.UtcNow - epochUtc).TotalSeconds); 

     // Add all the OAuth headers and querystring parameters, we'll need to use when constructing the hash. 
     var query = url.Split('?'); 
     if (query.Count() > 1) 
     { 
      if (data == null) data = new Dictionary<string, string>(); 
      var pairs = query[1].Split('&'); 
      foreach (var pair in pairs) 
      { 
       var keyvalue = pair.Split('='); 
       data.Add(keyvalue[0], keyvalue[1]); 
      } 
     } 
     data.Add("oauth_consumer_key", consumerKey); 
     data.Add("oauth_signature_method", "HMAC-SHA1"); 
     data.Add("oauth_timestamp", timestamp.ToString()); 
     data.Add("oauth_nonce", rand.Next(10000000, 999999999).ToString()); 
     data.Add("oauth_token", accessToken); 
     data.Add("oauth_version", "1.0"); 

     // Generate the OAuth signature and add it to our payload. 
     data.Add("oauth_signature", GenerateSignature(fullUrl, data, httpMethod)); 

     // Build the OAuth HTTP Header from the data. 
     string oAuthHeader = GenerateOAuthHeader(data); 

     switch (httpMethod) 
     { 
      case HttpMethod.GET: 
       return SendRequest(fullUrl, oAuthHeader, null, httpMethod); 
      case HttpMethod.POST: 
       var formData = new FormUrlEncodedContent(data.Where(kvp => !kvp.Key.StartsWith("oauth_"))); 
       return SendRequest(fullUrl, oAuthHeader, formData, httpMethod); 
      default: return null; 
     } 
    } 

    /// <summary> 
    /// Generate an OAuth signature from OAuth header values. 
    /// </summary> 
    string GenerateSignature(string url, Dictionary<string, string> data, HttpMethod httpMethod) 
    { 
     var sigString = string.Join(
      "&", 
      data 
       .Union(data) 
       .Select(kvp => string.Format("{0}={1}", WebUtility.UrlEncode(kvp.Key), WebUtility.UrlEncode(kvp.Value))) 
       .OrderBy(s => s) 
     ); 

     string urlWithoutParameters = url.Split('?')[0]; 

     var fullSigData = string.Format(
      "{0}&{1}&{2}", 
      httpMethod.ToString(), 
      Uri.EscapeDataString(urlWithoutParameters), 
      Uri.EscapeDataString(sigString.ToString()) 
     ); 

     return Convert.ToBase64String(sigHasher.ComputeHash(new ASCIIEncoding().GetBytes(fullSigData.ToString()))); 
    } 

    /// <summary> 
    /// Generate the raw OAuth HTML header from the values (including signature). 
    /// </summary> 
    string GenerateOAuthHeader(Dictionary<string, string> data) 
    { 
     return "OAuth " + string.Join(
      ",", 
      data 
       .Where(kvp => kvp.Key.StartsWith("oauth_")) 
       .Select(kvp => string.Format("{0}=\"{1}\"", Uri.EscapeDataString(kvp.Key), Uri.EscapeDataString(kvp.Value))) 
       .OrderBy(s => s) 
     ); 
    } 

Quelqu'un peut-il voir ce que je fais mal ici?

Répondre

0

aha a découvert la solution peu après sa publication. le problème dans mon cas est que le querystring est en train d'être encodé, mais cela doit apparemment correspondre exactement à l'url qui fait la demande. Comme je ne suis pas en train d'encoder l'URL, je reçois l'erreur.

Je dois modifier le code pour UrlEncode les valeurs de chaîne de requête dans l'URL d'origine afin qu'elles correspondent à ce qui est soumis dans la signature.

ici est une solution rapide et sale qui m'a permis de continuer:

Task<string> SendRequest(string url, HttpMethod httpMethod, Dictionary<string, string> data) 
    { 
     var fullUrl = TwitterApiBaseUrl; 

     // ... 

     var query = url.Split('?'); 
     if (query.Count() > 1) 
     { 
      fullUrl += query[0] + "?"; 
      if (data == null) data = new Dictionary<string, string>(); 
      var pairs = query[1].Split('&'); 
      foreach (var pair in pairs) 
      { 
       var keyvalue = pair.Split('='); 
       data.Add(keyvalue[0], keyvalue[1]); 
       fullUrl += keyvalue[0] + "=" + WebUtility.UrlEncode(keyvalue[1]) + "&"; 
      } 

      fullUrl = fullUrl.TrimEnd('&'); 
     } 
     else 
     { 
      fullUrl += url; 
     } 

     // ... 
    } 

Espérons que cela est utile à quelqu'un d'autre!