みむらです。
ひとまず、おべんきょーということで、後からも分かるように、
変数を多く使って文字列出力をふんだんに出しながら。
ソースコードが、海から来た侵略者に侵略されていますが、
そんなもの全く気にしない、むしろ、侵略されていないでゲソ!
サンプルコードは前の記事に。
Twitter の OAuth 1.0 認証を自分でコード書いてやってみた。
—-
参考資料:
* http://oauth.net/core/1.0
* http://hueniverse.com/oauth/guide/authentication/
* https://dev.twitter.com/docs/auth/authorizing-request/
—-
・・・あほみたいに長くなることが判明したので、この辺で記事を分割しておきます。
見たい方は「続きを読む」から。
下記の部分で触れる各変数、およびパラメータは、特に断りがなければ以下のようになっています。
変数名 |
説明 |
consumer_key (oauth_consumer_key) |
Consumer Key (Client Identifier)
アプリケーションを一意に示すのに用いられる値。 |
consumer_secret | Consumer Secret (Client Secret)
Consumer Key に紐づけられた、検証目的で利用される値。 |
access_token (oauth_token) |
Access Token
リクエストをする際に用いる、 (認証時に一意な値が発行される。) |
access_secret (oauth_token_secret) |
Access Secret
Access Token に紐づけられた、検証目的で利用される値。 |
request_token (oauth_token) |
Request Token
Access Token / Secret を取得するために一時的に発行される値。 |
request_secret (oauth_token_secret) |
Request Secret
Request Token に紐づけられた、検証目的で利用される値。 |
nonce (oauth_nonce) |
Nonce
処理ごとに違う、任意の値を指定する。 |
unixtime (oauth_timestamp) |
Time stamp
UNIX 時間 (1979-01-01 UTC からの秒数) |
signature (oauth_signature) |
Signature
整合性チェックのために、 |
(oauth_signature_method) | Signature Method
Signature を作るためのハッシュ関数を指定。 (Twitter の場合は HMAC-SHA1 のみ) |
(oauth_version) | Version
今回は 1.0 を利用します。 |
tweet_data (status) |
Status
つぶやく内容。 |
hwr | HttpWebRequest 型のインタフェース。 これを使って通信します。 |
param | パラメータ文字列を格納。 |
1.Token を取得する。
つぶやくために必要なアクセストークンを取得するために、
Twitter 側に「取得するための一時的なトークン」を発行してもらうプロセスです。
このステップでは、 Twitter の 「 https://api.twitter.com/oauth/request_token 」 に、
https://api.twitter.com/oauth/request_token?oauth_consumer_key=oDcUp76alv6VctYvRx2g&oauth_nonce=2179941686152750588&oauth_signature=dC61tOolE2kkHbQilqY7zvrnoRA=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1322307481&oauth_version=1.0
というようなリクエストを POST で行います。
参考: https://dev.twitter.com/docs/api/1/post/oauth/request_token
Random rand = new Random(); byte[] nonce_b = new byte[64]; rand.NextBytes(nonce_b); string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString(); long unixtime = GetUNIXTime(); // // OAuth Signature 生成のために、それ以外で仮のリクエスト文字列を作成する。 // この際、各パラメータは ABC 順にソートされている必要がある。 // string signature_request = "POST&" + UrlEncode("https://api.twitter.com/oauth/request_token"); signature_request += "&" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, null, null, null)); // // ちゃんとしたリクエスト文字列を作る。 // string signature = GetSignature(consumer_secret, null, signature_request); string param = MakeParamString(consumer_key, nonce, signature, unixtime, null, null, null); // // 問い合わせ。 // HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/oauth/request_token?" + param); hwr.Method = "POST"; WebResponse ret = hwr.GetResponse(); verify_token = new StreamReader(ret.GetResponseStream()).ReadToEnd().Split('&'); ret.Close();
先頭5行で、 UNIX 時間の取得と、ランダムな数字列を生成しています。
Random rand = new Random(); byte[] nonce_b = new byte[64]; rand.NextBytes(nonce_b); string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString(); long unixtime = GetUNIXTime();
nonce_b に生成された 64byte 分の数字列を Int64 型に変換し、 abs で絶対値に変換した後、
文字列に変換しています。
static long GetUNIXTime() { return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
GetUNIXTime() 関数はこのような感じ。 UNIX Time の定義そのままです。
次の4行でリクエスト文字列の作成をしています。
// // OAuth Signature 生成のために、それ以外で仮のリクエスト文字列を作成する。 // この際、各パラメータは ABC 順にソートされている必要がある。 // string signature_request = "POST&" + UrlEncode("https://api.twitter.com/oauth/request_token"); signature_request += "&" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, null, null, null)); // // ちゃんとしたリクエスト文字列を作る。 // string signature = GetSignature(consumer_secret, null, signature_request); string param = MakeParamString(consumer_key, nonce, signature, unixtime, null, null, null);
MakeParamString 関数は次のような感じ:
// パラメータ文字列を生成 static string MakeParamString(string oauth_consumer_key, string oauth_nonce, string oauth_signature, long oauth_timestamp, string oauth_token, string oauth_verifier, string status) { string param = "oauth_consumer_key=" + oauth_consumer_key + "&oauth_nonce=" + oauth_nonce; if (oauth_signature != null) param += "&oauth_signature=" + oauth_signature; param += "&oauth_signature_method=HMAC-SHA1" + "&oauth_timestamp=" + oauth_timestamp; if (oauth_token != null) param += "&oauth_token=" + oauth_token; if (oauth_verifier != null) param += "&oauth_verifier=" + oauth_verifier; param += "&oauth_version=1.0"; if (status != null) param += "&status=" + status; return param; }
つまり、
oauth_consumer_key=oDcUp76alv6VctYvRx2g&oauth_nonce=1155890576800496532&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1322307152&oauth_version=1.0
みたいな文字列を生成しています。
ただこの際、各パラメータは ABC 順にソートされている必要があります。
(されていないと受理されません。)
UrlEncode 関数は次のような感じ:
static string UrlEncode(string str) { string s = HttpUtility.UrlEncode(str); return _UrlEncodeUpper(s); } static string _UrlEncodeUpper(string str) { int p = str.IndexOf("%"); if (p != -1) { str = str.Substring(0, p) + str.Substring(p, 3).ToUpper() + _UrlEncodeUpper(str.Substring(p + 3)); } return str; }
要は、.net の標準ライブラリを用いて URL エンコードを行った後、
再起を利用して %以降の2文字を大文字に置換しています。
ここまでで、 signature_request 変数( Signature を生成するための文字列 )には、
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_consumer_key%3DoDcUp76alv6VctYvRx2g%26oauth_nonce%3D3863326961439002923%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1322307289%26oauth_version%3D1.0
というような文字列が入ります。
GetSignature 関数は次のような感じ:
static string GetSignature(string consumer_secret, string access_secret, string param) { HMACSHA1 hmacsha1 = new HMACSHA1(); hmacsha1.Key = Encoding.ASCII.GetBytes(consumer_secret + "&" + access_secret); byte[] hash = hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(param)); return Convert.ToBase64String(hash); }
HMACSHA1クラス
( http://msdn.microsoft.com/ja-jp/library/system.security.cryptography.hmacsha1(v=vs.80).aspx )
これを使って、ハッシュをとります。
この際の、生成キーは次の文字列になります。
[consumer_secret]&[access_token_secret]
このキーを用いて先ほど signature_request 変数に格納されている文字列についてハッシュを生成します。
ここまで作成が終わったら、パラメータ文字列を生成し直して、
oauth_consumer_key=oDcUp76alv6VctYvRx2g&oauth_nonce=2336380648701352887&oauth_signature=YVFCKdmCaljBmurjzFeJv5XCeRQ=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1322308083&oauth_version=1.0
https://api.twitter.com/oauth/request_token に投げると、
oauth_token=BIYmRMZKhdeZ4hale29OplkF0GjA881suM4g0wQ&oauth_token_secret=cKmEjN45oulQd6mJ3j57T1hDeUL1npV5Zjzgxe7s4js&oauth_callback_confirmed=true
という文字列が帰ってきますので、
このうち oauth_token と oauth_token_secret が
それぞれ Access Token / Secret を取得するために必要になる、Request Token / Secret になります。
2. Access Token を取得する。
1で取得した Request Token / Secret を元に、
つぶやくのに必要な、 Access token / Request を取得するプロセスです。
このステップでは、 ブラウザでユーザ認証を行い、 PIN を入力してもらった後、
これらのデータを https://api.twitter.com/oauth/access_token に、
oauth_consumer_key=oDcUp76alv6VctYvRx2g&oauth_nonce=3892287381380482420&oauth_signature=tslyAJpnMxhZNfmusKxzH8YKfsY=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1322308659&oauth_token=H5Awad7SVzUHGkA4tNCDEAi3YFBOvtXZ7z1WNNVCY&oauth_verifier=0712398&oauth_version=1.0
このような文字列を送信します。
参考 : https://dev.twitter.com/docs/api/1/post/oauth/access_token
string request_token = ""; string request_secret = ""; // // ブラウザ開いて認証。 // foreach (string s in verify_token) { int p = s.IndexOf("oauth_token="); if (p != -1) { request_token = s.Substring(p + "oauth_token=".Length); break; } } Process.Start("https://twitter.com/oauth/authorize?oauth_token=" + request_token); // // PIN を入力させる。 // Console.Write("\nINPUT PIN : "); string pin = Console.ReadLine(); foreach (string s in verify_token) { int p = s.IndexOf("oauth_token_secret="); if (p != -1) { request_secret = s.Substring(p + "oauth_token_secret=".Length); break; } } // // 以下 Twitter ともくもく通信。 // Random rand = new Random(); byte[] nonce_b = new byte[64]; rand.NextBytes(nonce_b); string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString(); long unixtime = GetUNIXTime(); // // Signature 生成のための一時的なリクエスト文字列を作成。 // string signature_request = "POST&" + UrlEncode("https://api.twitter.com/oauth/access_token"); signature_request += "&" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, request_token, pin, null)); string signature = GetSignature(consumer_secret, request_secret, signature_request); string param = MakeParamString(consumer_key, nonce, signature, unixtime, request_token, pin, null); // // 問い合わせ。 // HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/oauth/access_token?" + param); hwr.Method = "POST"; hwr.Headers.Add("Authorization", "OAuth"); WebResponse ret = hwr.GetResponse(); verify_token = new StreamReader(ret.GetResponseStream()).ReadToEnd().Split('&'); ret.Close(); foreach (string s in verify_token) { if (s.IndexOf("oauth_token=") != -1) access_token = s.Substring(s.IndexOf("=") + 1); if (s.IndexOf("oauth_token_secret=") != -1) access_secret = s.Substring(s.IndexOf("=") + 1); }
まず始めに、
先ほど取得した Request Token を元に、ブラウザで
https://twitter.com/oauth/authorize?oauth_token=[request_token]
にアクセスさせます。
そうしますと、今回の場合こんなのが出てきますので、「認証」
出てきた文字列を打ってもらう。
あとはそれを元に、pin を oauth_verifier=pin として付け加えて、次のような文字列を作り、
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Faccess_token&oauth_consumer_key%3DoDcUp76alv6VctYvRx2g%26oauth_nonce%3D7576447428639206328%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1322309766%26oauth_token%3D9WSdHNafGF0uRHbkgW7i1jDaMRyVRggwg1T6wzElTI%26oauth_verifier%3D9525882%26oauth_version%3D1.0
上記の文字列から Signature を生成して、次のようにパラメータ文字列を作り直し、
oauth_consumer_key=oDcUp76alv6VctYvRx2g&oauth_nonce=7576447428639206328&oauth_signature=Ft4AgiIaRONzOkHmJ1P9IAE3N7s=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1322309766&oauth_token=9WSdHNafGF0uRHbkgW7i1jDaMRyVRggwg1T6wzElTI&oauth_verifier=9525882&oauth_version=1.0
https://api.twitter.com/oauth/access_token に投げると、
oauth_token=77219798-*************&oauth_token_secret=*****************************&user_id=77219798&screen_name=mimura1133
というような文字列が帰ってきます。
この際の oauth_token および oauth_token_secret は、
Access Token および Access Secret になります。
(この値は表に出ると大変衛生上よろしくないので、伏せ字にしています。)
3.つぶやく。
つぶやきます。
このステップでは、 https://api.twitter.com/1/status/update.xml に、
Authorization: OAuth oauth_consumer_key="oDcUp76alv6VctYvRx2g",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1322310097",oauth_nonce="1334809891491345235",oauth_version="1.0",oauth_token="77219798-********************",oauth_signature="**********************",
というようなヘッダを付けて、
status=%E3%82%B2%E3%82%BD%E3%83%BC%E3%82%B2%E3%82%BD%E3%83%BC&include_entities=true
というようなデータを送信します。
ただ今回はURL にくっつけるのではなく、
POST https://api.twitter.com/1/statuses/update.xml HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: api.twitter.com Authorization: OAuth oauth_consumer_key="iOQHfiCUsyOyamW8JJ8jg",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1322297289",oauth_nonce="5194364",oauth_version="1.0",oauth_token="77219798-**********************",oauth_signature="***********************", Content-Length: 110 status=%E3%81%A7%E3%82%93%E3%81%A7%E3%82%89%E3%82%8A%E3%82%85%E3%83%BC%E3%81%B0%E3%83%BC&include_entities=true
こんな感じのリクエストになります。
Random rand = new Random(); byte[] nonce_b = new byte[64]; rand.NextBytes(nonce_b); string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString(); long unixtime = GetUNIXTime(); string tweet_data = UrlEncode(tweet_text); string signature_request = "POST&" + UrlEncode("https://api.twitter.com/1/statuses/update.xml"); signature_request += "&include_entities%3Dtrue%26" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, access_token, null, tweet_data)); string signature = GetSignature(consumer_secret, access_secret, signature_request); string header_param = "OAuth oauth_consumer_key=\"" + UrlEncode(consumer_key) + "\",oauth_signature_method=\"HMAC-SHA1\"," + "oauth_timestamp=\"" + unixtime + "\",oauth_nonce=\"" + UrlEncode(nonce) + "\"," + "oauth_version=\"1.0\",oauth_token=\"" + UrlEncode(access_token) + "\"," + "oauth_signature=\"" + UrlEncode(signature) + "\","; HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/1/statuses/update.xml"); hwr.Method = "POST"; hwr.ServicePoint.Expect100Continue = false; hwr.Headers.Add(HttpRequestHeader.Authorization, header_param); hwr.ContentType = "application/x-www-form-urlencoded"; var s = new StreamWriter(hwr.GetRequestStream()); s.Write("status=" + tweet_data + "&include_entities=true"); s.Close(); WebResponse ret = hwr.GetResponse();
まずは、つぶやく内容を URLEncode して、送信するデータを作成します。
次に、 “ status=[つぶやく中身] “として追加し、パラメータ文字列を作り、 Signature を計算します。
POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.xml&include_entities%3Dtrue%26oauth_consumer_key%3DoDcUp76alv6VctYvRx2g%26oauth_nonce%3D1334809891491345235%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1322310097%26oauth_token%3D77219798-****************************%26oauth_version%3D1.0%26status%3D%25E3%2582%25B2%25E3%2582%25BD%25E3%2583%25BC%25E3%2582%25B2%25E3%2582%25BD%25E3%2583%25BC
次に、HTTP リクエストのヘッダにくっつける、認証情報を作成します。
string header_param = "OAuth oauth_consumer_key=\"" + UrlEncode(consumer_key) + "\",oauth_signature_method=\"HMAC-SHA1\"," + "oauth_timestamp=\"" + unixtime + "\",oauth_nonce=\"" + UrlEncode(nonce) + "\"," + "oauth_version=\"1.0\",oauth_token=\"" + UrlEncode(access_token) + "\"," + "oauth_signature=\"" + UrlEncode(signature) + "\",";
文字列としては、
OAuth oauth_consumer_key="oDcUp76alv6VctYvRx2g",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1322310097",oauth_nonce="1334809891491345235",oauth_version="1.0",oauth_token="77219798-*****************",oauth_signature="****************",
このように、
hogehoge="gesogeso"
みたいな文字列を、カンマで区切った形の文となります。
この際、 Signature を URLEncode してあげる必要があります。
エンコードを忘れたり、ヘッダに付ける文字列が正しく無かったりすると、
Invalid … という文字列が帰ってきたり、
Could not authenticase with OAuth.
というエラーが、送信したときに Twitter 側から帰ってきます。
全部生成が完了したら、
https://api.twitter.com/1/status/update.xml に対して送信する際、
Header について以下の要素を指定します。
ContentType に application/x-www-form-urlencoded を指定し、
Authorization に 先ほど header_param に生成した文字列を指定します。
hwr.Headers.Add(HttpRequestHeader.Authorization, header_param); hwr.ContentType = "application/x-www-form-urlencoded";
そして、 Message 部分に
status=[つぶやく内容を URL エンコードしたもの]&include_entities=true
を付けて送信します。
全部完了すると、ちゃんとつぶやかれます。
ということで、サンプルコードは、前の記事を参照してください。
Twitter の OAuth 1.0 認証を自分でコード書いてやってみた。
ではではー。