Posts tagged: 未完成

C#でOAuth認証でTwitterにpost

このエントリーをはてなブックマークに追加
はてなブックマーク - C#でOAuth認証でTwitterにpost

【追記】2010/5/12 生成後のsignatureをパーセントエンコードしていなかったミスを修正
signature生成に必要なパラメータは大文字、signature自体は小文字でURLエンコードする必要があったようだ。

————————————————————————-
C#でOAuth認証でTL取得とほとんど変わらない。
signatureを生成するとき、signature生成前にstatus(post本文)をURLエンコードしておかないとうまく認証されないみたい。

これでひとまずぼとすたやらシャナbotのOAuthへの移行へめどが立った。
おかしなところ指摘していただけると助かります。

Read more »

このエントリーをはてなブックマークに追加
はてなブックマーク - C#でOAuth認証でTwitterにpost

C#でOAuth認証でTL取得

このエントリーをはてなブックマークに追加
はてなブックマーク - C#でOAuth認証でTL取得

【追記】2010/5/12 生成後のsignatureをパーセントエンコードしていなかったミスを修正
signature生成に必要なパラメータは大文字、signature自体は小文字でURLエンコードする必要があったようだ。

————————————————————————-

tokenとtoken_secretが取得できたところで、TwitterAPIをOAuth認証で利用してタイムラインを取得してみた。
basic認証とは違ってsignatureの生成が面倒だが、そのほかはほとんど変わらない。

まずは以下のパラメータと、consumer_secret,token_secretを利用してsignatureを生成する。

  • oauth_consumer_key(登録時に発行)
  • oauth_nonce(ランダムな毎回異なる8文字以上の英数字)
  • oauth_token(ここで取得)
  • oauth_version(“1.0″を指定)
  • oauth_timestamp(取得時間をUNIX時刻で)
  • oauth_signature_method(“HMAC-SHA1″を指定)
  • 各種APIで使うパラメータ(pageとかsince_idとか)

signatureの生成には、各種APIで使うパラメータ(pageとかsince_idとか)も含めたパラメータを使う。

signatureBaseはこんなかんじになる。
詳しくは検索で・・・だが、HttpMethodとエンコード済みのURL、エンコード済みのパラメータを連結したものを連結。
ここらへんが参考になった。


GET&http%3A%2F%2Ftwitter.com%2Fstatuses%2Ffriends_timeline.xml&oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3DNONCE%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DTIMESTAMP%26oauth_token%3DTOKEN%26oauth_version%3D1.0%26page%3D2



ハッシュ値を求める際のキーには、consumer_secreとtoken_secretをURLエンコードし、&で結んだものを使用する。
signatureを生成したら、上記パラメータとsignatureをAPIに送るだけ。

例えばこんな感じで送る。


oauth_consumer_key=CONSUMER_KEY&oauth_nonce=NONCE&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272290458&oauth_token=TOKEN&oauth_version=1.0&page=2&oauth_signature=CaQiJNAfkdIlfb3MxeF1F0P+jqg=

以下、コード。とりあえず動くレベル。


class OAuthTwitter
{
    const string consumer_key = "**********************";
    const string consumer_secret = "**********************";
    const string token = "**********************";
    const string token_secret = "**********************";

    //APIのURLとパラメータでAPIにアクセス
    private string GetAPI(string APIURL)
    {
        return GetAPI(APIURL, null);
    }

    //APIのURLとパラメータでAPIにアクセス
    private string GetAPI(string APIURL, Dictionary<string, string> query)
    {
        string result, queryString;
        result = queryString = string.Empty;

        //signature生成
        string signature = GenerateSignature(APIURL, "GET", query, consumer_secret, token_secret, out queryString);

        //生成したsignatureは小文字でパーセントエンコード
        string postString = queryString + string.Format("&oauth_signature={0}", UrlEncodeSmall(signature));

        //取得開始    
        byte[] data = Encoding.ASCII.GetBytes(postString);        
        WebRequest req = WebRequest.Create(string.Format("{0}?{1}",APIURL,postString));
        WebResponse res;
        try
        {
            res = req.GetResponse();
            Stream stream = res.GetResponseStream();
            StreamReader reader = new StreamReader(stream);
       
            result = reader.ReadToEnd();
            reader.Close();
            stream.Close();
        }
        catch (WebException ex)
        {
            if (ex.Status == WebExceptionStatus.ProtocolError)
            {
                if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Unauthorized)
                {
                    /*401 Unauthorized                    
                    *認証失敗*/

                    return "401 Unauthorized";
                }
                else if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.BadRequest)
                {
                    /*400 Bad Request                    
                    *リクエストが不正*/

                    return "400 Bad Request";
                }  
            }
            else
            {
                return ex.Message;
            }
                   
        }
        return result;
    }

    //APIのURL,HttpMethod(POST/GET),パラメータ,consumer_secret,token_secretでsignature生成
    private string GenerateSignature(string url, string httpMethod, Dictionary<string, string> query, string consumer_secret, string token_secret, out string conectedQuery)
    {
        //SortedDictionaryでパラメータをkey順でソート
        SortedDictionary<string, string> sortedParams;
        if(query==null)
            sortedParams = new SortedDictionary<string, string>();
        else
            sortedParams = new SortedDictionary<string, string>(query);
   
        string timestamp = GenerateTimestamp();
        string nonce = GenerateNonce();
   
        sortedParams["oauth_consumer_key"] = consumer_key;
        sortedParams["oauth_token"] = token;
        sortedParams["oauth_version"] = "1.0";
        sortedParams["oauth_timestamp"] = timestamp;
        sortedParams["oauth_nonce"] = nonce;
        sortedParams["oauth_signature_method"] = "HMAC-SHA1";
   
        StringBuilder sb = new StringBuilder();
        bool first = true;
        foreach (var p in sortedParams)
        {
            if (first)
            {
                sb.Append(p.Key + "=" + p.Value);
                first = false;
            }
            else
                sb.Append(@"&" + p.Key + "=" + p.Value);
        }
        conectedQuery = sb.ToString();
        sstring signatureBace = string.Format(@"{0}&{1}&{2}", httpMethod, UrlEncode(url),UrlEncode(sb.ToString()));

        //consumer_secretとtoken_secretを鍵にしてハッシュ値を求める
        HMACSHA1 hmacsha1 = new HMACSHA1();
        hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode(consumer_secret), UrlEncode(token_secret)));
        byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(signatureBace);
        byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
   
        return Convert.ToBase64String(hashBytes);
    }

    private string GenerateNonce()
    {
        string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder result = new StringBuilder(8);
        Random random = new Random();
        for (int i = 0; i < 8; ++i)
            result.Append(letters[random.Next(letters.Length)]);
        return result.ToString();
    }

    private string GenerateTimestamp()
    {
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        return Convert.ToInt64(ts.TotalSeconds).ToString();
    }

    private string UrlEncode(string value)
    {
        string unreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        StringBuilder result = new StringBuilder();
        byte[] data = Encoding.UTF8.GetBytes(value);
        foreach (byte b in data)
        {
            if (b < 0x80 && unreserved.IndexOf((char)b) != -1)
                result.Append((char)b);
            else
                result.Append('%' + String.Format("{0:X2}", (int)b));
        }
        return result.ToString();
    }
    private string UrlEncodeSmall(string value)
    {
        string unreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

        StringBuilder result = new StringBuilder();
        byte[] data = Encoding.UTF8.GetBytes(value);
        foreach (byte b in data)
        {
            if (b < 0x80 && unreserved.IndexOf((char)b) != -1)
                result.Append((char)b);
                else
                result.Append('%' + String.Format("{0:x2}", (int)b));
            }
        return result.ToString();
        }
    }

class Program
{
     static void Main(string[] args)
    {
        System.Net.ServicePointManager.Expect100Continue = false;
       
        Dictionary<string,string> query = new Dictionary<string,string>();
        query["page"] = "2";
        OAuthTwitter oauthTwitter = new OAuthTwitter();      

        //TwitterAPIを利用してタイムライン取得
        Console.WriteLine(oauthTwitter.GetAPI("http://twitter.com/statuses/friends_timeline.xml",query));      
   }
}

このエントリーをはてなブックマークに追加
はてなブックマーク - C#でOAuth認証でTL取得

Dansette