ラベル OAuth の投稿を表示しています。 すべての投稿を表示
ラベル OAuth の投稿を表示しています。 すべての投稿を表示

2011年6月6日月曜日

PHPでOAuthをやっつける方法

前々回のOAuthについてまとめてみた、前回のJavaでOAuthをやっつける方法に続いて今回はPHPでOAuth認証を利用したAPIへのアクセスを実装してみる。

今回も、天下のoauth.netのoauthライブラリ(Google Code)を使う。oauthのリポジトリからOAuth.phpを持ってくれば準備完了。


すぐ使いたい時

Java版と併せてライブラリにまとめてみたのでここ(Google Code)から取得してもらうと、簡単に実装できる。HowToUse.phpを見てもらうのが手っ取り早いけど、How to use for phpにも触りだけ書いてあるのでよかったら見てください。


やること

  • 各種の設定を定義
  • リクエストトークンを取得する
  • ユーザーにアプリケーションを承認してもらう
  • アクセストークンを取得する

各種の設定を定義

サービスプロバイダーのエンドポイント情報やコンシューマの情報を、下記のように定義する。

$TOMOKEY = array(
  'CONSUMER_KEY' => 'anonymous',
  'CONSUMER_SECRET' => 'anonymous',
  'CONSUMER_CALLBACK_URL' => 'oob',
  'REQUEST_TOKEN_URL'
    => 'https://www.google.com/accounts/OAuthGetRequestToken',
  'USER_AUTHORIZATION_URL'
     => 'https://www.google.com/accounts/OAuthAuthorizeToken',
  'ACCESS_TOKEN_URL'
     => 'https://www.google.com/accounts/OAuthGetAccessToken'
);
※Goole Data APIをクライアントアプリから利用する例なので、ウェブアプリの場合とかはJavaでOAuthをやっつけるを参照。

リクエストトークンを取得する

Step1.コンシューマ情報をオブジェクト化

// consumer info
$consumer_key
  = $consumer_config['CONSUMER_KEY'];
$consumer_secret
  = $consumer_config['CONSUMER_SECRET'];
$consumer_callback
  = $consumer_config['CONSUMER_CALLBACK_URL'];

// OAuthConsumerオブジェクトを構築
$consumer
  = new OAuthConsumer(
      $consumer_key,
      $consumer_secret,
      $consumer_callback);
Step2.署名ツールを生成
// 署名方式はHMAC-SHA1
$signature_method = new OAuthSignatureMethod_HMAC_SHA1();
※今回はよく使うSHA-1方式にしとく。
Step3.パラメータを生成
$params
  = array(
      'oauth_callback'
        => $consumer->callback_url,
      'scope'
        => 'https://www.google.com/calendar/feeds/');
※Google Calendar APIにアクセスする例なので、scopeというパラメータも設定してる。
Step4.リクエストオブジェクトを生成
$request
  = OAuthRequest::from_consumer_and_token(
      $consumer,
      NULL, // RequestToken取得時は不要
      'GET',
      $TOMOKEY['REQUEST_TOKEN_URL'],
      $params);

// 署名する
$request->sign_request($signature_method, $consumer, NULL);
※先につくっておいたOAuthConsumerオブジェクト、パラメータを使ってリクエストオブジェクトを生成し、署名ツールで署名を行う。
Step5.HTTP通信を行う。
// cURLリソースの生成
$ch = curl_init();
// Locationヘッダは無視
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
// サーバ証明書の検証を行わない
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// レスポンスを文字列として取得する設定
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// (出力結果に)ヘッダを含めない
curl_setopt($ch, CURLOPT_HEADER, false);
// URLを指定
curl_setopt($ch, CURLOPT_URL, $request->to_url());

// 実行
$result = curl_exec($ch);

// close curl resource to free up system resources
curl_close($ch);

// レスポンスを解析
parse_str($result, $result_map);

// リクエストトークンを取得
$req_token
  = new OAuthToken(
      $result_map['oauth_token'],
      $result_map['oauth_token_secret']);
※POSTで送信する場合には、CURLOPT_URLには、to_url()の代わりにget_normalized_http_url()を使うのと、CURLOPT_HTTPHEADERにarray($request->to_header)ってな感じでAuthorizationパラメータ設定が必要。その他の詳細はコード(httpという名称のfunction)を参照。

ユーザーにアプリケーションを承認してもらう

下記のように作成したURLに対して、ブラウザでアクセスしてもらう。PHPならheaderでリダイレクトするのが一般的なのかな?

// サービスプロバイダーが定義しているエンドポイント
$auth_url = $TOMOKEY['USER_AUTHORIZATION_URL'];

// ここで作成したURLにアクセスしてもらう
$url
  = $auth_url .
    '?' .
    OAuthUtil::build_http_query(array('oauth_token' => $req_token->key));
※承認画面が表示されて、ポチっとした後はcallback URLにリダイレクト or 画面にverifier表示。

アクセストークンを取得する

Step1.色々

リクエストトークンの取得と同じ手順でコンシューマ情報のオブジェクト化と署名ツールの生成を行う。 ちなみに、取得しておいたリクエストトークンは、この後使うのでセッションとかデータストアとかを使って保存しておく必要がある。
Step2.パラメータを生成
$params
  = array('oauth_verifier' => $verifier);
※ここで使用している$verifierは、ユーザー承認により取得した文字列のこと。callback URLが指定されているなら、リダイレクト先にoauth_verifierとして送信される。
Step3.リクエストオブジェクトを生成
$request
  = OAuthRequest::from_consumer_and_token(
      $consumer,
      $req_token, // 保存しておいたリクエストトークンオブジェクト
      'GET',
      $TOMOKEY['ACCESS_TOKEN_URL'],
      $params);

// 署名する
$request->sign_request($signature_method, $consumer, $req_token);
※リクエストトークンの取得時と異なるのは3点。
  • URLがACCESS_TOKEN_URL
  • リクエストトークンを送信する
  • 署名鍵としてリクエストトークンのシークレットの方も利用する
Step4.HTTP通信を行う。
この手順は前述と同じ。最後に取得できるのがアクセストークンってとこだけ違う。

終わり

アクセストークンを使ってAPIアクセス方法は、アクセストークンの取得手順でリクエストトークンの代わりにアクセストークンを指定した場合と同じ。
だけど、リダイレクトの考慮をしないとGoogle Calendar APIとかは使えないので、コード(invokeという名称のfunction)をご参照あれ。

2011年6月3日金曜日

JavaでOAuthをやっつける方法

前回、OAuthについてまとめてみたので、今度は実際にOAuth認証を利用したAPIへのアクセスをJavaで実装してみる。

今回は、天下のoauth.netのoauthライブラリ(Google Code)を使う。

oauthのリポジトリからcommons、consumer、httpclient4を持ってくる。

OAuthのライブラリはいくつかあるみたいだけど、Javaのコードを書く場合はAndroidアプリやGoogle App Engineなどにも移植可能なものがよさげ。
(Jakarta Commons HttpClient v4にてOAuth認証を組み込むとコードがすっきりする。一方、GAEではHttp Client v4が使えなかったりする。こういった違いを吸収できるとこがイイ)


やること

いっぱい。。。

  • consumer.propertiesを用意
  • consumer.propertiesを読み込む
  • リクエストトークンを取得する
  • ユーザーにアプリケーションを承認してもらう
  • アクセストークンを取得する

consumer.propertiesを用意

まず、サービスプロバイダーのエンドポイント情報やコンシューマの情報を、下記のようなconsumer.propertiesファイルに定義する。(適当な名前を付ける。例ではtomokey)

tomokey.consumerKey: consumer_key
tomokey.consumerSecret: consumer_secret
tomokey.callbackURL: oob
tomokey.serviceProvider.baseURL: https://www.google.com/
tomokey.serviceProvider.requestTokenURL: /accounts/OAuthGetRequestToken
tomokey.serviceProvider.userAuthorizationURL: /accounts/OAuthAuthorizeToken
tomokey.serviceProvider.accessTokenURL: /accounts/OAuthGetAccessToken
この設定内容は、各サービスプロバイダーや利用形態で異なる。

Google Data APIをWebアプリケーションから利用する場合

consumer key発行されたもの
consumer secret発行されたもの
callback URLverifierを受け取るURL
request token URLhttps://www.google.com/accounts/OAuthGetRequestToken
user authorization URLhttps://www.google.com/accounts/OAuthAuthorizeToken
access token URLhttps://www.google.com/accounts/OAuthGetAccessToken

Google Data APIをクライアントアプリケーションから利用する場合

consumer keyanonymous
consumer secretanonymous
callback URLoob
request token URLhttps://www.google.com/accounts/OAuthGetRequestToken
user authorization URLhttps://www.google.com/accounts/OAuthAuthorizeToken
access token URLhttps://www.google.com/accounts/OAuthGetAccessToken

consumer.propertiesを読み込む

// クラスローダーを生成
ClassLoader loader = ClassLoader.getSystemClassLoader();
// 設定ファイルのURLを取得
URL url = loader.getResource("consumer.properties");
// 読み込み
Properties prop = ConsumerProperties.getProperties(url);

// tomokeyという名前の付いた設定を読み込む
ConsumerProperties consumers = new ConsumerProperties(prop);
OAuthConsumer consumer = consumers.getConsumer("tomokey");

リクエストトークンを取得する

// OAuthClient
OAuthClient client = new OAuthClient(new HttpClient4());

// OAuth accessor
OAuthAccessor accessor = new OAuthAccessor(consumer);

// パラメータを構築
List<Parameter> params = new ArrayList<Parameter>();
// oauth_callbackを追加
params.add(new Parameter(
    OAuth.OAUTH_CALLBACK,
    accessor.consumer.callbackURL));

// リクエストトークン取得を要求
client.getRequestToken(accessor, "GET", params);

// 取得したリクエストトークン
String token = accessor.requestToken;
String secret = accessor.tokenSecret;
ライブラリを使っているおかげでだいぶ簡潔になっているけど、本当は色々とやってくれている。具体的には、下記のことをやっている。
base stringの構築
これらの文字列を全部連結する。
  • HTTPリクエストメソッド(POSTとかGET)
  • アクセスURL
  • 全リクエストパラメータを「key=value」形式にしてkeyでソートして「&」でくっつける…
oauth_signatureの構築
デフォルトのSHA-1アルゴリズムでbase stringに対するハッシュ値を計算し、base64エンコードをかけて生成する。
SHA-1の鍵にはconsumer secretの末尾に「&」を付与したものを用いる。
HTTPリクエストの構築と実行
oauth_signatureを含む全てのパラメータをBODY部に設定し、Content-Type:application/x-www-form-urlencodedとしてリクエストを発行する。
APIに依っては、パラメータをHEADER部に行わなければならない場合もあるので、consumer.propertiesに「tomokey.consumer.parameterStyle: AUTHORIZATION_HEADER」とか設定すると吉。


ユーザーにアプリケーションを承認してもらう

これはアプリケーションの形態に依存すると思う(Androidアプリならhttp/httpsのインテントを投げるとか)けど、いずれにしても下記のように作成したURLに対して、ブラウザでアクセスしてもらう必要がある。

// サービスプロバイダーが定義しているエンドポイント
String authUrl
  = accessor.consumer.serviceProvider.userAuthorizationURL;

// ここで作成したURLにアクセスしてもらう
String url
  = OAuth.addParameters(authUrl, OAuth.OAUTH_TOKEN, token);
大抵の場合は承認ボタンがあるのでポチっとしてもらう。その後、Webアプリケーション(callbackURLが設定されている)の場合は、そのURLへのアクセス時にパラメータとしてverifierが送信される。(リダイレクトされる)

クライアントアプリケーション(callbackURLがoob)の場合は、画面にverifierが表示される。(ユーザーにコピペしてもらう必要がある)


アクセストークンを取得する

// OAuthClient
OAuthClient client = new OAuthClient(new HttpClient4());

// OAuth accessor
OAuthAccessor accessor = new OAuthAccessor(consumer);

// SHA1の鍵にリクエストトークンのシークレットのほうが必要
accessor.tokenSecret = secret;

// パラメータを構築
List<Parameter> params = new ArrayList<Parameter>();
// oauth_tokenとしてリクエストトークンを追加
params.add(new Parameter(
    OAuth.OAUTH_TOKEN,
    token));
// oauth_verifierを追加
params.add(new Parameter(
    OAuth.OAUTH_VERIFIER,
    "ベリファイア"));

// アクセストークン取得を要求
client.getAccessToken(accessor, "GET", params);

// 取得したアクセストークン
String accToken = accessor.accessToken;
String accSecret = accessor.tokenSecret;
リクエストトークンの取得と似ているけど、注意点がいくつかある。
  • accessor.tokenSecretにリクエストトークンのシークレットのほうを設定する。(SHA1ハッシュ計算時に使う鍵として利用)
  • リダイレクトかコピペかで入力してもらったベリファイアをパラメータとして設定する。

終わり

一応、アクセストークンを使ってAPIアクセスするコードものっけておく。

// URL(Fusion Tables API)
String url = "https://www.google.com/fusiontables/api/query";

// パラメータ
List<Parameter> params
  = OAuth.newList("sql", "SELECT * FROM 913439");

// OAuthClient
OAuthClient client = new OAuthClient(new HttpClient4());

// OAuth accessor
OAuthAccessor accessor = new OAuthAccessor(consumer);

// アクセストークンを設定
accessor.accessToken = accToken;
accessor.tokenSecret = accSecret;

// リクエストオブジェクト生成
OAuthMessage request
  = accessor.newRequestMessage("POST", url, aParams);

// 実行
OAuthMessage response
  = client.access(request, ParameterStyle.AUTHORIZATION_HEADER);
但し、リダイレクトの考慮をしていないので注意。

ライブラリにして公開した

すぐ上に書いてあるリダイレクトの考慮をした上で、ちょっと便利っぽくライブラリにまとめてみた。 ここ(Google Code)からダウンロード可能。

OAuthとは何か?

OAuth(1.0)については、ゼロから学ぶOAuthとかAPIアクセス権を委譲するプロトコル、OAuthを知るあたりで色々と説明されているけど、忘れた時にふと読み返すには少し記事が長いと思う。

今回は、ざっくりとOAuthとは何か、その承認プロセスはどんな感じかを自分なりに短くまとめてみる。


何をするためのものか

例えば、自分のGoogleカレンダーを見やすく表示してくれるアプリケーションがあったとする。これを利用するには、アプリケーションの入手の他に、Googleカレンダーデータの取得が必要になる。

Googleカレンダーデータの取得を実現する一番簡単な方法は、アプリケーションにGoogleのIDとパスワードを設定すること。でも、IDとパスワードをアプリケーションに設定するのがちょっとイヤな場合がある。Webアプリケーションなどがそれ。

そんな時、OAuthを使うとGoogleのIDとパスワードをアプリケーションに教えることなく、やりたいことが実現できる。


OAuthのプレイヤー

OAuthでは、下記3つのプレイヤーが鍵になってくる。

サービスプロバイダー

GoogleやTwitterなどに代表されるサービスプロバイダーは、OAuthにおいて最も重要な役割を担っている。エンドポイントの提供、各種トークンやベリファイアの発行を行う。

コンシューマ
サービスプロバイダーが提供するAPIを利用してユーザーのデータを扱うアプリケーション。

ユーザー
アプリケーション利用者であり、サービスプロバイダーに会員登録をしている。


OAuthで使用する要素

OAuthを実装するにあたって基本的な要素を理解する必要性がある。

トークン(token/token secret)

トークンとトークンシークレットで1組の鍵データであり、コンシューマトークン、リクエストトークン、アクセストークンの3種類が存在する。

コンシューマトークン(consumer token/consumer token secret)
サービスプロバイダーがアプリケーションに対して発行するもの。アプリケーションを識別するために利用する。

リクエストトークン(request token/request token secret)
リサービスプロバイダーがアプリケーションに対して一時的に発行するもの。ユーザーがアプリケーションを承認するプロセスでのみ利用する。

アクセストークン(access token/access token secret)
サービスプロバイダーがアプリケーションに対して発行するもの。ユーザーデータにアクセスし放題になる重要情報。アクセストークンさえあればOAuthを利用した各種APIの利用が可能になる。

ベリファイア(verifier)
ユーザーがアプリケーションを承認するプロセスの最終段階で利用するもの。PINコードと呼ばれたりする。サービスプロバイダーがユーザーに対して発行するものであり、さらにユーザーがアプリケーションに渡し、最後にアプリケーションがリクエストトークンとセットでサービスプロバイダーに投げつける。

エンドポイント(Endpoint)
サービスプロバイダーが公開しているOAuth認証プロセスに必要な機能を備えたURI。リクエストトークンを発行するためのエンドポイント、ユーザーが承認を行うためのエンドポイント、アクセストークンを発行するためのエンドポイントが存在する。

OAuth 1.0 API Reference(Google)とかTwitter REST API Method: oauth request_token(Twitter)に書いてある。


承認プロセス

まず、アプリケーションの登録

アプリケーションの登録方法はサービスプロバイダーによって違うけど、基本的には専用のWebサイトでアプリ登録を行い、コンシューマトークンを得るという作業になる。

Googleの場合

ここにアクセスし、画面の指示に従う。が、完全なクライアントアプリケーションを作りたいよーという場合には、すっとばしてOK。コンシューマトークンには"anonymous"という文字列を利用すれば良い。

Twitterの場合
ここにアクセスし、画面の指示に従う。Twitterの場合はWebアプリケーションでもクライアントアプリケーションでも同じ。



リクエストトークンの取得

リクエストトークンを発行するためのエンドポイントに対して、必要なパラメータを設定したHTTPリクエストを発行し、レスポンスとしてリクエストトークンを得る。



ベリファイアの取得

ユーザーが承認を行うためのエンドポイントへユーザーにアクセスしてもらう。その際、oauth_tokenパラメータとして先に取得したリクエストトークンを付与する。ユーザーが承認を行うとベリファイアを得ることができる(サービスプロバイダのサイト上に表示されるか、指定したURLへのリダイレクトかのいずれか)。



アクセストークンの取得

アクセストークンを発行するためのエンドポイントに対して、必要なパラメータを設定したHTTPリクエストを発行し、レスポンスとしてアクセストークンを得る。



終わり

この長い旅路を終えて得たアクセストークンが、OAuthを認証方式に採用しているAPIを利用するために必要なものになる。