3

Windows 8 と、ソーシャル メディア ダッシュボードとして機能する Windows Phone 8 アプリがあり、Twitter 検索 API を使用してツイートを取得します。これはもともと Twitter API 1 を使用して実装され、認証なしで機能したため、追加のサードパーティ ライブラリは必要なかったため、ソリューションの PCL 部分に配置されました。同じ理由で、1.1 API を使用するための更新をライブラリなしで実行したかったのです。Twitter 開発者コミュニティや codeproject でさまざまなサンプルをオンラインで見つけて、PCL で動作するように修正しました。

以下は、Twitter を検索しようとするコードの一部です。

private static async Task<string> doTheTwitterMagic(string query)
    {
        var oauth_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_consumer_key = "XXXXXXXXXXXXXXXXX";
        var oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        var resource_url = "https://api.twitter.com/1.1/search/tweets.json";

        // oauth implementation details
        var oauth_version = "1.0";
        var oauth_signature_method = "HMAC-SHA1";

        Encoding ascii = new AsciiEncoding();

        // unique request details
        var oauth_nonce = Convert.ToBase64String(
            ascii.GetBytes(DateTime.Now.Ticks.ToString()));
        var timeSpan = DateTime.UtcNow
            - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();


        // create oauth signature
        var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
                        "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&q={6}";

        var baseString = string.Format(baseFormat,
                                    oauth_consumer_key,
                                    oauth_nonce,
                                    oauth_signature_method,
                                    oauth_timestamp,
                                    oauth_token,
                                    oauth_version,
                                    Uri.EscapeDataString(query)
                                    );

        baseString = string.Concat("GET&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString));

        var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                                "&", Uri.EscapeDataString(oauth_token_secret));

        string oauth_signature;
        using (HMACSHA1 hasher = new HMACSHA1(ascii.GetBytes(compositeKey)))
        {
            oauth_signature = Convert.ToBase64String(
                hasher.ComputeHash(ascii.GetBytes(baseString)));
        }

        // create the request header
        var headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
                           "oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
                           "oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
                           "oauth_version=\"{6}\"";

        var authHeader = string.Format(headerFormat,
                                Uri.EscapeDataString(oauth_nonce),
                                Uri.EscapeDataString(oauth_signature_method),
                                Uri.EscapeDataString(oauth_timestamp),
                                Uri.EscapeDataString(oauth_consumer_key),
                                Uri.EscapeDataString(oauth_token),
                                Uri.EscapeDataString(oauth_signature),
                                Uri.EscapeDataString(oauth_version)
                        );

        return authHeader;
    }
public static async Task<List<TwitterObject>> GetTweetsFromSearchAsync(string query)
    {
        try
        {
            string authHeader = await doTheTwitterMagic(query);

            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://api.twitter.com/1.1/search/tweets.json?q="+query);
            webRequest.Headers[HttpRequestHeader.Authorization] = authHeader;
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";

            var webResponse = await webRequest.GetResponseAsync();
            var json = string.Empty;
            using (var reader = new StreamReader(webResponse.GetResponseStream()))
                json = await reader.ReadToEndAsync();

            var jsonObject = JObject.Parse(json);
            var results = new List<TwitterObject>();
            foreach (JToken token in jsonObject["results"])
                results.Add(token.ToObject<TwitterObject>());
            return results;
        }
        catch (Exception e) { throw e; }
    }

注意: AsciiEncoding は ASCIIEncoding のカスタム実装です。現時点では PCL で使用できないためです。

ここで、標準のデバッグを試みました。最初に見たのは Twitter OAuth ツールでした。これが OAuth ツールと私のアプリの結果です。

OAuth ツール署名の基本文字列:

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3D3c30afb0c2a391d3b4e4ba3da057c2ca%26oauth_
signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1371309728%26oauth_token%3D16702
294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3Dcsmcr

私のアプリ署名ベース文字列:

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3DNjM1MDY5MTA1MzA2MTU1NTgz%26oauth_signatur
e_method%3DHMAC-SHA1%26oauth_timestamp%3D1371310131%26oauth_token%3D16702294-3WNj
fZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3D%2540csmcr

そして、最初に見た唯一の違いはノンスですが、それは問題ではないはずです 編集メモ: OAuth ツールの 1 つに % がある場合、両方の最後に上記に小さな違いがあることに気付きました26q%3Dcsmcr で、私のアプリは %26q%3D%2540csmcr を生成しますが、これは、OAuth ツールのクエリに文字を含めるのを忘れたためです。文字を追加した後、文字列は最後に同じになりました。

OAuth ツールの Authorization ヘッダー:

Authorization: OAuth oauth_consumer_key="ywWuYGASkHMsHsC22Vpw",    
oauth_nonce="3c30afb0c2a391d3b4e4ba3da057c2ca", 
oauth_signature="tofmGp6qaAUAPZnQHhQlVFWN40M%3D", 
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309728", 
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM", 
oauth_version="1.0"

私のアプリの承認ヘッダー:

Authorization: OAuth oauth_nonce="NjM1MDY5MDk5NTY5Nzc1MTc5", 
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309557", 
oauth_consumer_key="ywWuYGASkHMsHsC22Vpw", 
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM", 
oauth_signature="q1544JDPUXdUwY3fmEk3mtGGEwk%3D", oauth_version="1.0"

ここでも、ナンスと署名以外に大きな違いはありません。キーと値のペアの順序は、それらを並べ替えてテストしたところ、同じ問題が発生したため、違いはないようです。

したがって、私が抱えている問題は、関数が実行されると、常に 401 Unauthorized エラーが発生することです

{"errors":[{"message":"Could not authenticate you","code":32}]}

エラー。

任意のポインタは非常に高く評価されます。

編集:これでさらにテストを行い、Twitter OAuthツールによって生成されたノンスとタイムスタンプを取得し、アプリでそれらをハードコーディングして、署名が問題ないかどうかを確認しました。 1 つは OAuth ツールにあります。これは、Auth ヘッダーもまったく問題ないことを意味します。したがって、問題は私のリクエストのどこかにあると思います。

4

1 に答える 1