Jersey OAuth を使って Twitter API にアクセスする

Jersey には OAuth で認証するためのモジュールが用意されています。今回はそれを使ってみた時のメモです。内容的には JAX-RS を使ったことがあることを想定しています。

まず、あらかじめ Twitter Developers でアプリケーションを登録して Consumer Key と Secret Key を手に入れておきます。また、OAuth サービスプロバイダ (今回は Twitter) での認証後にリダイレクトしてもらう URI を登録しておきましょう。
https://dev.twitter.com/

OAuth を使うのに必要な jar は以下の 3 つ。Jersey の Web サイトや、あるいは Maven を使ってリモートリポジトリから手に入れておきます。
http://jersey.java.net/

oauth-client-{version}.jar
oauth-server-{version}.jar
oauth-signature-{version}.jar

JavaDoc は以下にあるようです。
http://jersey.java.net/nonav/apidocs/1.10/contribs/jersey-oauth/oauth-signature/index.html?com/sun/jersey/oauth/signature/package-summary.html

方法は幾つか用意されているようですが、今回は OAuthClientFilter を使う方法を試してみました。OAuthClientFilter は Jersey Client と併せて使います。

OAuth の認証では、まず OAuth サービス・プロバイダの URI にユーザをリダイレクトします。リダイレクトする先の URI は、先ほど手に入れたアプリケーションの Consumer Key と Secret Key を使って手に入れます。コード例では XXX にしてあります。
せっかく Jersey の OAuth モジュールを使うので JAX-RS で WebAPI の形式で作ってみました。

	@GET
	public Response auth() throws OAuthSignatureException, URISyntaxException {
		OAuthParameters params = new OAuthParameters()
				.signatureMethod("HMAC-SHA1")
				.consumerKey("XXX").version();
		OAuthSecrets secrets = new OAuthSecrets()
				.consumerSecret("XXX");
		OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(),
				params, secrets);
		WebResource resource = Client.create()
				.resource("https://api.twitter.com/oauth/request_token");
		resource.addFilter(filter);
		String redirectQuery = resource.get(String.class);
		return Response
				.status(302)
				.location(
						new URI("https://api.twitter.com/oauth/authorize?"
								+ redirectQuery)).entity("redirect").build();
	}

先ほど作った WebAPI の URI に HTTP GET すると Twitter の認証ページにリダイレクトされます。ユーザがリダイレクト先のページで認証すると、あらかじめ Twitter Developer に登録しておいた URI にリダイレクトされて戻ってきます。もちろんリダイレクトされる URI はあらかじめ作っておく必要があります。

リダイレクトされる URI ではクエリパラメータの形で Request Token が得られます。JAX-RS を使うのでクエリパラメータの値を @QueryParam アノテーションを使って得ます。得られた Request Key は Access Key に交換します。

	@GET
	@Path("/redirect")
	@Produces("text/plain; charset=UTF-8")
	public Response redirect(@QueryParam("oauth_token") String oauthToken, @QueryParam("oauth_verifier") String oauthVerifier) {
		OAuthParameters params = new OAuthParameters().signatureMethod("HMAC-SHA1").
		consumerKey("XXX").version();
		params.setToken(oauthToken);
		params.setVerifier(oauthVerifier);
		OAuthSecrets secrets = new OAuthSecrets().consumerSecret("XXX");
		Client client = Client.create();
		OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);
		WebResource resource = client.resource("https://api.twitter.com/oauth/access_token");
		resource.addFilter(filter);
		String response = resource.get(String.class);

この String response が Access Key です。クエリパラメータの形式で得られるため、パースしてセッションにでも保存しておきましょう。必要な値は "oauth_token" と "oauth_token_secret" です。

この Access Key の "oauth_token" と "oauth_token_secret" を使って Twitter API にアクセスできます。ここでは Map queryMap に Access Key が保存されているとします。例えば Home timeline を取得するコードは以下のようになります。

		Client client = Client.create();
		OAuthParameters params = new OAuthParameters().signatureMethod("HMAC-SHA1").
		consumerKey("XXX").version();
		params.setToken(queryMap.get("oauth_token"));
		OAuthSecrets secrets = new OAuthSecrets().consumerSecret("XXX").tokenSecret(queryMap.get("oauth_token_secret"));
		OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);
		WebResource resource = client.resource("https://api.twitter.com/1/statuses/home_timeline.json");
		resource.addFilter(filter);
		String response = resource.get(String.class);

この例では String 形式でマーシャリングしていますが、実際には各 API で得られる表現ごとに Java Bean を定義して、それを使うことになります。

ちなみに今回は Google App Engine を使ってサンプルアプリケーションを作ってみました。ホームタイムラインをただ JSON 形式で表示するだけなので見てもなんのこっちゃという感じですが…。はじめて Google App Engine を使ってみましたが HelloWorl まで 30 分くらいでできました。便利すぎてやばいです。
http://jersey-oauth-test.appspot.com/

以下のサイトを参考にしました。
OAuth - Jersey: RESTful Web services made easy - wikis.sun.com
ゼロから学ぶOAuth:第1回 OAuthとは?―OAuthの概念とOAuthでできること