OAuth::Liteを使って、はてなのOAuth対応APIを使ってみる。
何はともあれ、まずは認証から。認証まわりの説明は以下にある。
AP登録
まず最初にAP登録が必要。はてなにログインして、以下のURLから登録する。
OAuth Consumer Key と OAuth Consumer Secret はAPごとに払い出されるので、これを使う。APの名称、説明、URLは後でも変更可能なので、デフォルトのままでもOK。
「新しいアプリケーションの追加」を実行すると、確認なしにAPが追加され、削除できないので要注意。私は無駄に一個作ってしまいました...
OAuth認証のシーケンス
OAuth 1.0 の認証シーケンスは以下の通り。
User User-Agent Consumer Service Provider (resource owner) | (client) (server) | | | | |-------->| | | | |------------------->* | | | | get_request_token | | | |------------------->| /initiate | | |<-------------------| | |<-------------------| | | |---------------------------------------->| /authorize | |<----------------------------------------| |<--------| | | | | | | |-------->| | | | |---------------------------------------->| | |<----------------------------------------| | |------------------->* | | | | get_access_token | | | |------------------->| /token | | |<-------------------| | |<-------------------| | |<--------| | | | | | |
get_request_token、get_access_token は OAuth::Lite::Consumer のメソッド名。
/initiate、/authorize、/token は、はてなの場合、以下の通り。
Request Token URL | https://www.hatena.com/oauth/initiate | (/initiate) |
User Authorization URL | https://www.hatena.ne.jp/oauth/authorize | (/authorize) |
Access Token URL | https://www.hatena.com/oauth/token | (/token) |
OAuth::Lite::Consumerオブジェクトの生成
いろんなパラメータが指定できるけど、consumer_key と consumer_secret だけ設定すればOK。
my $consumer = new OAuth::Lite::Consumer( consumer_key => $consumer_key, consumer_secret => $consumer_secret, );
$consumer_key と $consumer_secret は、AP登録のときに払い出された OAuth Consumer Key と OAuth Consumer Secret を使う。この2つはの値は外部に漏らさないよう注意。なりすましクライアントが作れてしまうからね。
Request Token の取得
get_request_token() をコールして Service Provider に Request Token を要求する。
my $request_token = $consumer->get_request_token( url => 'https://www.hatena.com/oauth/initiate', callback_url => $cgi->url, scope => 'read_public,write_public', ) or die $consumer->errstr."\n";
url には Request Token URL を指定する。callback_url には認証後にリダイレクトするコールバックURLも指定する(上の例では自分自身のURLを指定)。また、はてなの場合、scope というパラメータも必要。scope に何が指定できるかは、
を参照のこと。
Request Token が取得できたら、セッションをまたがって使用するために、何らかの方法で保存しておく。Request Token は OAuth::Lite::Token のオブジェクトなので、as_encoded() と from_encoded() でシリアライズできる。保存方法としてCookieを使ってもいいかもしれないけど、oauth_token_secret はネットワークに不用意に流さない方がいいと思う。
認証URLへリダイレクト
url_to_authorize() をコールして User Authorization URL へリダイレクトするためのURLを生成し、ブラウザにリダイレクトを指示する。
print $cgi->redirect( $consumer->url_to_authorize( url => 'https://www.hatena.ne.jp/oauth/authorize', token => $request_token, ));
url には User Authorization URL を指定する(はてなではデバイスに応じて選択可能)。token には先ほど取得した Request Token を設定する。
リダイレクト先のページではAPの情報が表示されるので、ユーザがアクセスの許可/拒否を選択できる。
Access Token の取得
ユーザによってアクセスが許可されると、コールバックURLが以下のパラメータを伴ってコールされる。
- oauth_token
- oauth_verifier
oauth_token は Request Token に含まれているものと同じなので、これを使ってセッション管理してもいいかも。
先ほど保存した Request Token を何らかの方法で復元し、それを使って get_access_token() をコールすることで Service Provider に Access Token を要求する。
my $access_token = $consumer->get_access_token( url => 'https://www.hatena.com/oauth/token', token => $request_token, verifier => $oauth_verifier, );
url には Access Token URL を指定する。token は復元した Request Token を設定、verifier はコールバック時のパラメータ oauth_verifier を指定する。
Access Token が取得できたら、いよいよAPIを使った操作に入るわけだが、それはまた後日にでも。
全体のコード
全体のコードはこうなりました。
#!/usr/bin/perl -T use strict; use CGI; use CGI::Carp qw(fatalsToBrowser); use OAuth::Lite::Consumer; use OAuth::Lite::Token; my $consumer_key = '________________'; my $consumer_secret = '____________________________'; my $title = 'Test Hatena OAuth API'; sub save_request_token { my ($request_token) = @_; open(TOKEN, ">.session") or die $!; print TOKEN $request_token->as_encoded; close(TOKEN); } sub load_request_token { open(TOKEN, ".session") or die $!; my $request_token = OAuth::Lite::Token->from_encoded(<TOKEN>); close(TOKEN); return $request_token; } my $cgi = new CGI; my $consumer = new OAuth::Lite::Consumer( consumer_key => $consumer_key, consumer_secret => $consumer_secret, ); if (! $cgi->param()) { my $request_token = $consumer->get_request_token( url => 'https://www.hatena.com/oauth/initiate', callback_url => $cgi->url, scope => 'write_public,read_private', ) or die $consumer->errstr."\n"; save_request_token($request_token); print $cgi->redirect( $consumer->url_to_authorize( url => 'https://www.hatena.ne.jp/oauth/authorize', token => $request_token, )); } else { my $oauth_verifier = $cgi->param('oauth_verifier'); my $request_token = load_request_token(); my $access_token = $consumer->get_access_token( url => 'https://www.hatena.com/oauth/token', token => $request_token, verifier => $oauth_verifier, ); print $cgi->header, $cgi->start_html(-title=>$title) . $cgi->h1($cgi->a({href=>$cgi->url},$title)) . $cgi->dl( $cgi->dt('Access Token:'), $cgi->dd($access_token->token), $cgi->dt('Access Secret:'), $cgi->dd($access_token->secret), ) . $cgi->end_html; }
セッションの保存のし方はとてもいい加減なので、良い子はまねしちゃいけません。