Google API 用のアクセストークンをサービスアカウントで取得 - Google API Client Library for Java

Google の各種 API を使うためのアクセストークンをサービスアカウントを使って取得してみました。

ライブラリは Google API Client Library for Java を使います。

ソースは http://github.com/fits/try_samples/tree/master/blog/20150608/

はじめに

今のところ Google API を使用するには以下のような方法があるようで、 今回は (1) の方法で行います。

番号 方法 用途 アクセストークンの取得方法 Google アカウントで API 利用
(1) サービスアカウント利用 サーバーアプリケーション JSON Web Tokens (JWTs) 制限あり
(2) Google アカウントで承認 Webサーバーアプリケーション, 組み込みアプリケーション Google アカウントで API 利用を承認 or リフレッシュトークン 可能

(1) の方法はログイン等を行わずに API を利用できる反面、API を自分の Google アカウントで利用したい場合には以下のような事をしなければならないようです。

どちらにしても、ドメインgmail.comGmail アカウント等へ成り代わるのは無理そうですし、サービスアカウントで使える API は限られるかもしれません。

※ 同じドメインに所属する全てのユーザーへ成り代わる権限を
   サービスアカウントへ付与する機能

(2) の方法は自分のアカウントで API を利用できますが、基本的に Web 画面でログインして API の利用を承認する必要があります。(ただし、初回のみ)

承認するとアクセストークン(有効期限あり)とリフレッシュトークン(有効期限なし)を取得できるので、次からはリフレッシュトークンでアクセストークンを取得し直す事ができます。

サービスアカウントの発行

まずは Google Developers Console へログインしサービスアカウントを発行します。

  1. プロジェクトを選択
  2. APIと認証」の「認証情報」をクリック
  3. 「新しいクライアントIDを作成」をクリック
  4. 「サービスアカウント」を選択し、「クライアントIDを作成」 をクリック (キータイプは JSON
  5. キーファイルを保存

JSON キーファイルの方が実装するコードが少なくなるので、今回は JSON キータイプ (デフォルト) を選んでいます。

アクセストークンの取得

JSON キーファイルを使ってアクセストークンを取得し、出力する処理は以下のようになります。

SampleApp.java
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;

import java.io.FileInputStream;
import java.util.Arrays;

public class SampleApp {
    public static void main(String... args) throws Exception {
        FileInputStream jsonKeyFile = new FileInputStream(args[0]);

        GoogleCredential credential = GoogleCredential.fromStream(jsonKeyFile)
                .createScoped(Arrays.asList("https://spreadsheets.google.com/feeds/"));
        // アクセストークンの取得
        credential.refreshToken();

        System.out.println("access token: " + credential.getAccessToken());
    }
}

createScoped を使ってアクセストークンで利用する API の URL を指定しています。 (今回は Google スプレッドシートAPI を指定)

refreshToken メソッドを実行する事でアクセストークンを取得します。

なお、refreshToken の実行前に getAccessToken メソッドを実行すると null を返します。

JSON キーファイルの代わりに P12 キーファイルを使う場合は GoogleCredential.Builder 等を使う事になります。

実行

Gradle による実行結果は以下の通りです。 (JSON キーファイルは sample.json です)

実行結果
> gradle -q run -Pargs=sample.json

access token:  yb17.iwR01J2W8Left-・・・

Gradle のビルド定義ファイルは以下の通りです。

build.gradle
apply plugin: 'application'

repositories {
    jcenter()
}

dependencies {
    compile 'com.google.api-client:google-api-client-java6:1.20.0'
}

mainClassName = 'SampleApp'

run {
    if (project.hasProperty('args')) {
        args project.args.split(' ')
    }
}

Google スプレッドシートAPI 利用 - REST

次は、アクセストークンを取得して Google スプレッドシートの単純な API を呼び出してみます。

スプレッドシート用のライブラリは使わず、Apache の HttpClient を使って https://spreadsheets.google.com/feeds/spreadsheets/private/full を GET しました。

アクセストークンは HTTP ヘッダー (Authorization) へ設定します。

SampleApp2.java
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;

import java.io.FileInputStream;
import java.util.Arrays;

public class SampleApp2 {
    private static final String SPREADSHEETS_FEED_BASE = 
            "https://spreadsheets.google.com/feeds/";
    private static final String SPREADSHEETS_FEED_FULL =
            SPREADSHEETS_FEED_BASE + "spreadsheets/private/full";

    public static void main(String... args) throws Exception {
        FileInputStream jsonKeyFile = new FileInputStream(args[0]);

        GoogleCredential credential = GoogleCredential.fromStream(jsonKeyFile)
                .createScoped(Arrays.asList(SPREADSHEETS_FEED_BASE));

        // アクセストークン取得
        credential.refreshToken();

        HttpClient client = HttpClientBuilder.create().build();

        HttpGet get = new HttpGet(SPREADSHEETS_FEED_FULL);
        // アクセストークンをヘッダーへ設定
        get.addHeader("Authorization", "Bearer " + credential.getAccessToken());

        HttpResponse res = client.execute(get);

        // 結果の出力
        res.getEntity().writeTo(System.out);
        System.out.println("");
    }
}

実行

実行結果は以下の通りです。

最初はサービスアカウントで使えるスプレッドシートが存在していないので以下のようになると思います。

実行結果1 (出力結果は見易いように加工しています)
> gradle -q run -Pargs=sample.json

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'>
  <id>https://spreadsheets.google.com/feeds/spreadsheets/private/full</id>
  <updated>2015-06-07T11:58:26.141Z</updated>
  <category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#spreadsheet'/>
  <title type='text'>Available Spreadsheets - ・・・</title>
  <link rel='alternate' type='text/html' href='http://docs.google.com'/>
  <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/spreadsheets/private/full'/>
  <link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/spreadsheets/private/full'/>
  <openSearch:totalResults>0</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
</feed>

Google スプレッドシートスプレッドシートを開き、「共有」をクリックして JSON キーファイルの client_email の値 (サービスアカウントのメールアドレス) を登録した後、再度実行してみると以下のようになりました。

実行結果2 (出力結果は見易いように加工しています)
> gradle -q run -Pargs=sample.json

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' ・・・>
  ・・・
  <entry>
    <id>https://spreadsheets.google.com/feeds/spreadsheets/private/full/・・・</id>
    <updated>2015-06-07T11:46:41.314Z</updated>
    <category scheme='http://schemas.google.com/spreadsheets/2006' ・・・ />
    <title type='text'>sample</title>
    <content type='text'>sample</content>
    ・・・
  </entry>
</feed>

Gradle のビルド定義ファイルは以下の通りです。

build.gradle
apply plugin: 'application'

repositories {
    jcenter()
}

dependencies {
    compile 'com.google.api-client:google-api-client-java6:1.20.0'
    compile 'org.apache.httpcomponents:httpclient:4.5'
}

mainClassName = 'SampleApp2'

run {
    if (project.hasProperty('args')) {
        args project.args.split(' ')
    }
}