Android(というかJava)で OAuth 認証を実装してみたので、手順をメモしました。
ここでは OAuth1.a での認証を想定してます。
1. OAuthライブラリをダウンロードする
OAuth とりわけ1.aは手順が複雑なので、ライブラリを使ったほうが楽です。
Java で使えるライブラリは、以下のようなものがあるみたいです。
※以降は oauth-signpost の実装例です。
上記URLから次の2つをダウンロードします。
(下記バージョンは、2013/10/17時点での最新です。)
- signpost-core-1.2.1.2.jar
- signpost-commonshttp4-1.2.1.2.jar
これらを Android プロジェクトに import します。
2. 認証するサービスの開発者登録をする
OAuth 認証するためには、ConsumerKey と ConsumerSecret の情報が必要です。
それらを取得するために、OAuth認証をするサービスの開発者サイトで、開発者登録をします。すると上記2つの情報に加え、アクセス先URLなどの情報も得ることが出来ます。
この後必要になるのは、主に以下の情報です。
- Consumer key
- Consumer secret
- Request token URL
- Authorize URL
- Access token URL
- Callback URL
3. ブラウザでユーザーに OAuth 認証してもらうコード
ユーザーのアカウント情報で OAuth 認証してもらうにあたり、ブラウザで認証画面を表示させるようにします。(ログイン画面を作る手間がかからないので。)
以下は該当する箇所のみ、抜粋したものです。
public class MainActivity extends Activity {
private static final String CONSUMER_KEY = "xxxx";
private static final String CONSUMER_SECRET = "xxxx";
private static final String REQUEST_TOKEN_URL = "xxxx";
private static final String AUTHORIZE_URL = "xxxx";
private static final String ACCESS_TOKEN_URL = "xxxx";
private static final String CALLBACK = "xxxx";
private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Oauth認証を開始
OAuthRequestAsyncTask oAuthAsyncTask = new OAuthRequestAsyncTask();
oAuthAsyncTask.execute();
}
/**
* OAuth認証の通信を行うクラス
*/
private class OAuthRequestAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void...arg0) {
// Oauth認証
try {
mConsumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
mProvider = new CommonsHttpOAuthProvider(REQUEST_TOKEN_URL, ACCESS_TOKEN_URL, AUTHORIZE_URL);
String authUrl = mProvider.retrieveRequestToken(mConsumer, CALLBACK);
// ブラウザに認証ページを開かせる
MainActivity.this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
return null;
}
}
4. 認証結果からアクセストークンを取得する
まずはブラウザからのコールバックを受け取れるように、AndroidManifest.xml に Intent-filter を定義します。
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="xxxx" android:host="xxxx" />
</intent-filter>
</activity>
<data>
で定義するのは、3 で定義している CALLBACK の URL と同じものを定義します。
例えば、 myapp://callback
という CALLBACK であれば、 scheme="myapp"
で host="callback"
となります。
launchMode="singleInstance"
は、何個も同じActivityを生成しないようにするための宣言です。
アクセストークンを取得するためのコールバック処理は、以下のようになります。
/**
* Intentからの起動
* @param intent
*/
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
// ブラウザ認証からのコールバック処理
if (uri != null && uri.toString().startsWith(CALLBACK)) {
// アクセストークン取得およびリクエスト処理
OAuthAccessAsyncTask oAuthAccessAsyncTask = new OAuthAccessAsyncTask();
oAuthAccessAsyncTask.execute(uri);
}
}
/**
* OAuth認証のコールバック処理を行うクラス
*/
private class OAuthAccessAsyncTask extends AsyncTask<Uri, Void, Void> {
@Override
protected Void doInBackground(Uri...uris) {
Uri uri = uris[0];
final String oauthVerifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
try {
// AccessToken取得
mProvider.retrieveAccessToken(mConsumer, oauthVerifier);
Log.d(TAG, "ACCESS_TOKEN : " + mConsumer.getToken());
Log.d(TAG, "ACCESS_TOKEN_SECRET : " + mConsumer.getTokenSecret());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
上記で Log に出力している AccessToken を使ってリクエストを送信するので、取得後は保存しておくと使い回しがし易いです。
5. OAuth認証結果を使ってAPIを呼び出す
APIを実際に呼び出す際には、リクエストデータを以下のように署名してから送信します。
HttpClient httpClient = new DefaultHttpClient();
String urlString = "xxxx";
HttpGet httpGet = new HttpGet(urlString);
// リクエストデータを署名する
mConsumer.sign(httpGet);
String responce = httpClient.execute(httpGet,
new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException {
// HttpStatus.SC_OK (HTTP200)
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
return EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
}
return null;
}
});
Log.d(TAG, "responce : " + responce);