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)からダウンロード可能。

0 件のコメント:

コメントを投稿