みむらです。
ひとまず、おべんきょーということで、後からも分かるように、
変数を多く使って文字列出力をふんだんに出しながら。
ソースコードが、海から来た侵略者に侵略されていますが、
そんなもの全く気にしない、むしろ、侵略されていないでゲソ!
サンプルコードは前の記事に。
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 認証を自分でコード書いてやってみた。
ではではー。