2012年8月1日水曜日

AndroidのAccountManagerを使ったOAuth2認証は何だか怪しい

AndroidのOSのアカウントマネージャ経由でのOAuth2を試してみたが、どうも怪しい。

まず、AccountManager経由でAuthTokenを取得する時authTokenType(OAuth2でいうところのscopeらしいが)をどう設定すればいいのか?

一応リストはある。しかし、GoogleのAPIの全てを網羅しているわけではない。

Frequently Asked Questions - Google Data APIs — Google Developers

例えば、「https://www.googleapis.com/auth/userinfo.profile」とか「 https://www.googleapis.com/auth/adsense.readonly」を使う場合どうすればいいのか?GoogleDriveは?

みんな完全なリストを相当探しているみたいだけど、まともなドキュメントは上の記事くらいしかないようだ。

自分も散々探しまわった挙句、上の記事のリストにないscopeを指定する方法が分かった。

OAuth2 - google-api-java-client - OAuth 2.0 - Google APIs Client Library for Java - Google Project Hosting

・・・The OAuth 2.0 scope is specified via the "authTokenType" as "oauth2:" plus the scope, for example "oauth2:https://www.googleapis.com/auth/tasks"・・・However, in prior Android SDKs, it will literally echo the authTokenType "oauth2:https://www.googleapis.com/auth/tasks" in the permission page. This will be fixed in the future, but for now that is the best you can do.if you need multiple OAuth 2.0 scopes, use a space-separated list.・・・

例えば「https://www.googleapis.com/auth/userinfo.profile」をauthTokenTypeに指定するには「oauth2:https://www.googleapis.com/auth/userinfo.profile」とURLの頭に「oauth2:」とつけて指定すればいいらしい。

これはできた。上の記事にあるコードを参考に一部のコードを書くとこんな風。

public void onClickBtn(View view) {
    String authTokenType = "oauth2:https://www.googleapis.com/auth/userinfo.email";
    //String authTokenType = "oauth2:https://www.googleapis.com/auth/userinfo.profile oauth2:https://www.googleapis.com/auth/userinfo.email";
    AccountManager am = AccountManager.get(this);
    am.getAuthTokenByFeatures("com.google", authTokenType, null, AccountManagerTestActivity.this, null, null,
        new AccountManagerCallback<Bundle>() {
          public void run(AccountManagerFuture<Bundle> future) {
            try {
              Bundle bundle = future.getResult();
              String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
              Log.v("run", "authToken=" + authToken);
              getUserInfo(authToken);
            } catch (Exception e) {
              Log.v("run", e.getMessage(), e);
            }
          }
        },
        null);
  }

ただし、注意書きがあるように、アプリケーションのアクセスを許可する画面でサービス名で出ず、URLがそのまま出てしまう。こんな感じ。


ICS以降だとちゃんとサービス名で出るようだけど試してない。

そしてGoogleアカウントの「Google アカウント に許可されたアクセス」を見ると、許可されたアプリケーションはこのように表示されることがわかった。


これは調子が悪いな(*´Д`)

さらに、scopeが複数ある場合はスペースで区切って指定すればいいようなことを書いてあるけど、複数指定するとこのような画面になって正しいパスワードを入力しても先へ進めなくなる。


AccountManagerを使えば、ユーザーに対してWebViewに表示するOAuth2の画面でユーザーIDやパスワードの入力を求めなくてよくなるものの、このような問題があることを考えるとAccountManagerは本当に実用的なのかどうか疑問だ。

他にうまいやり方があるのだろうか?

AccountManagerに依存するとこのような問題や、Google版エミュでしか動作させることができず、より高速なx86版エミュも使えなくなる。

琴線探査: Androidのエミュレーターでアカウントを追加する2つの方法

OSのバージョンごとに動作が変わってきそうだというところも気になる。

うーん。どうしたもんか・・・

追記12.08.06:こちらのブログはAccountManager経由での認証について詳しい
Switch Your Coding Life: Android - Account manager - Part I