2010年2月13日土曜日

mixiにOAuthなRESTfulアクセス(Java)

最近サービスづいてきています。OAuthばっかりです。
今度はJavaでmixiにアクセスです!

まず、、、RESTful APIでアクセスするには
まずmixiアプリの登録が必要です。

http://developer.mixi.co.jp/appli/pc/pc_prepare/add_app_flow

アプリケーションを登録できたら、
アプリケーションに対してConsumer KeyとConsumer Secretが発行されます。

これを元にOAuthアクセスを行います。

まずHMAC-SHA1と呼ばれる暗号化を行う為のインスタンスを生成します。

  1. byte[] secretyKeyBytes = secret.getBytes("UTF-8");  
  2. secretKeySpec = new SecretKeySpec(secretyKeyBytes,hmac);  
  3. mac = Mac.getInstance(hmac);  
  4. mac.init(secretKeySpec);  


ここでのsecretはConsumer Secretに「&」を付与したものになります。
secretKeySpecはjavax.crypto.spec.SecretKeySpecになります。
macはjavax.crypto.Macですね。

URLに設定する引数を作成します。

  1. params.put("oauth_consumer_key", KEY);  
  2. params.put("oauth_signature_method""HMAC-SHA1");  
  3. params.put("oauth_timestamp", String.valueOf(cal.getTimeInMillis()).substring(0,10));  
  4. params.put("oauth_version""1.0");  
  5. params.put("oauth_nonce", nonce);  
  6. params.put("xoauth_requestor_id", viewerId);  
  7. params.put("format""atom");  


このparamsはURLを作成する為のオリジナルクラスのマップです。

oauth_consumer_keyに設定しているKEYはConsumer Keyですね。
oauth_signature_methodは暗号化を示す"HMAC-SHA1"を固定で指定します。
oauth_timestampは時刻を設定します。
oauth_versionはmixiに指定された文字列
oauth_nonceはリクエスト毎に違うランダムな文字列です。UUID.randomUUID().toString()などで生成します。
xoauth_requestor_idは対象のユーザIDです。
formatはatomを設定していますが、最終的に取得するデータの形式でjsonでも取得できます。


次にシグネチャを取得する為の文字列を取得します。

  1. String method = "GET";  
  2. String http   ="http://" + endpoint + requestURI ;  
  3. String args   = canonicalQS;  
  4. String toSign;  
  5. try {  
  6.     toSign = URLEncoder.encode(method,"UTF-8")+"&"+  
  7.                     URLEncoder.encode(http,"UTF-8")+"&"+  
  8.                     URLEncoder.encode(args,"UTF-8");  
  9. catch (UnsupportedEncodingException e) {  
  10.     throw new RuntimeException(e);  
  11. }  


endpointはmixiのエンドポイント、、、って公開して良いのかな?
requestURIは/people/{id}/@allです。{id}は取得したい人のIDを設定します。
canonicalQSは前に設定したマップから取得したURLの引数です。

これらの文字列をそれぞれURLエンコードして”&”で連結します。

その文字列を最初に作ったmacを元にしてシグネチャを作成します。

  1. String signature = null;  
  2. byte[] data;  
  3. byte[] rawHmac;  
  4. try {  
  5.     data = stringToSign.getBytes(CHARSET);  
  6.     rawHmac = mac.doFinal(data);  
  7.     Base64 encoder = new Base64();  
  8.     signature = new String(encoder.encode(rawHmac));  
  9.  signature = signature.substring(0, hmac.length()-2);  
  10. catch (UnsupportedEncodingException e) {  
  11.     throw new RuntimeException(CHARSET + " is unsupported!", e);  
  12. }  
  13.   
  14. try {  
  15.     signature = URLEncoder.encode(signature, CHARSET).replace("+""%20")  
  16.             .replace("*""%2A").replace("%7E""~");  
  17. catch (UnsupportedEncodingException e) {  
  18. }  


この文字列には改行が入ってますので2文字削除しています。
そのあと、文字列の変換をかけてます。

で、、、作成されたシグネチャを元に、アクセスするURLを作成します。

  1. String url = "http://" + endpoint + requestURI + "?" + canonicalQS + "&oauth_signature=" + sig;  


でここにアクセスするとそのユーザの情報がXML化されて取得できるってわけです。
但し、ここで問題が発生します。
アクセスすると401エラーが返ってきます。

だので、、、mixiアプリの事を調べていくと。。。

  1. 対象ユーザが対象のmixiアプリを起動していない、もしくは起動から一定時間が経過した後にRESTful APIにアクセスを行った際には、  
  2. HTTPレスポンスコードとして「401 Unauthorized」が返却されます。  


ををを、、、そういう事なのね。
ようはしばらくmixiアプリを起動した人の情報を
xoauth_requestor_idに設定してあげないと
アクセスできないってわけです。

APIを使うにはいろいろ画面遷移を考えないときついっぽいですね。
しかしこれでアクセスできました。
さぁ問題は何を作るかですね。。。。。



OAuthの仕様は
http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/1/spec.html
にあります。

シグネチャがうまく取れるまで結構かかりました。
なのでここにある仕様(文字列)を元にテストを書きました。

実際のコードはその他サービスなどにアクセスしている為
複雑なクラスになっているのを平たく記述しているので
ペローンって感じのコードになっていますが、テストは通ります。




元のコードは
http://bit.ly/bVSEgt
なども参考にしています。

0 件のコメント: