Google アカウントで Google API を利用 - google-api-services-gmail

前回はサービスアカウントを使う方法を試しましたが、今回は Google アカウントを使って Google API を利用してみます。

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

はじめに

API 利用までの手順は次の通りです。

  • (1) クライアント ID を発行
  • (2) Google アカウントで API の利用を承認し、コードを取得
  • (3) (2) で取得したコードを使ってリフレッシュトークンを取得
  • (4) (3) で取得したリフレッシュトークンからアクセストークンを取得し API を利用

基本的に (2) と (3) は (API を利用する) Google アカウント毎に 1回だけ実施します。

(3) でアクセストークンも取得できますが、アクセストークンには有効期限があるため、通常は (4) でリフレッシュトークンからアクセストークンを取得し直します。

(1) クライアント ID を発行

Google Developers Console へログインし、ネイティブ アプリケーション用のクライアント ID を発行します。

  1. プロジェクトを選択
  2. APIと認証」の「認証情報」をクリック
  3. 「新しいクライアントIDを作成」をクリック
  4. 「インストールされているアプリケーション」を選択し、「クライアントIDを作成」 をクリック (アプリケーションの種類は "その他")
  5. JSON をダウンロード」をクリックしファイルを保存

保存した JSON ファイルは後の処理で使用します。

サービスアカウントで取得した JSON ファイルとは中身が異なりますのでご注意ください。

JSON ファイルの例
{
    "installed":{
        "auth_uri":"https://accounts.google.com/o/oauth2/auth",
        "client_secret":"・・・",
        "token_uri":"https://accounts.google.com/o/oauth2/token",
        "client_email":"",
        "redirect_uris":["urn:ietf:wg:oauth:2.0:oob","oob"],
        "client_x509_cert_url":"",
        "client_id":"・・・.apps.googleusercontent.com",
        "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"
    }
}

(2) Google アカウントで API 利用を承認し、コードを取得

この作業は基本的に Web 画面を使って行います。

https://accounts.google.com/o/oauth2/auth?redirect_uri=<リダイレクト先URL>&response_type=code&client_id=<クライアントID>&scope=<利用するAPIのURL> へアクセスし、Google アカウントでログインして API の承認画面で 「承認」 ボタンをクリックします。

scope には承認する API の URL を %20 (半角スペースを URLエンコードしたもの) 区切りで指定します。

以下のように PhantomJS 等を利用し UI レスで実施する事も一応可能でしたが、Captcha の入力があった場合等には使えませんので実用性は低めだと思います。

approve_api.groovy
@Grab('org.gebish:geb-core:0.10.0')
@Grab('com.codeborne:phantomjsdriver:1.2.1')
import geb.Browser
import org.openqa.selenium.phantomjs.PhantomJSDriver
import org.openqa.selenium.remote.DesiredCapabilities

import groovy.json.JsonSlurper

def json = new JsonSlurper()
def conf = json.parse(new File(args[0])).installed

def userId = args[1]
def password = args[2]
// Gmail の API を承認するためのスコープ設定
def scope = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.modify'
].join('%20')

def code = null

Browser.drive {
    setDriver(new PhantomJSDriver(new DesiredCapabilities()))

    def url = "${conf.auth_uri}?redirect_uri=${conf.redirect_uris[0]}&response_type=code&client_id=${conf.client_id}&scope=${scope}"

    go url
    // メールアドレス入力
    $('input[name="Email"]').value(userId)
    $('input[type="submit"]').click()

    // パスワード入力画面に変わるまで待機
    waitFor(30) { $('div.second div.slide-in').isDisplayed() }

    // パスワード入力
    $('input[name="Passwd"]').value(password)
    $('div.second input[type="submit"]').click()

    // API の承認ボタンが有効になるまで待機
    waitFor(30) { $('button[id="submit_approve_access"]').isDisabled() == false }

    // 承認ボタンをクリック
    $('button[id="submit_approve_access"]').click()

    def codeInput = waitFor(30) { $('input[id="code"]') }

    // コードを取得
    code = codeInput.value()

    quit()
}
println code

PhantomJS を実行できるように環境変数 PATH を設定し実行します。

コマンドライン引数の第1引数には (1) で保存した JSON ファイルを指定します。

実行例
> groovy approve_api.groovy client_secret.json xxxx@gmail.com ****
・・・

4/3vJ9・・・

(3) リフレッシュトークンの取得

(2) で取得したコードを使ってリフレッシュトークンを取得します。

https://www.googleapis.com/oauth2/v3/token へコードなどの情報を POST すれば、JSON データとしてアクセストークンとリフレッシュトークンを取得できます。

client_id, client_secret, redirect_uri の値には (1) で保存した JSON ファイル内の情報を使っています。

get_refresh-token.groovy
@Grab("org.apache.httpcomponents:httpclient:4.5")
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods.HttpPost
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.message.BasicNameValuePair

import groovy.json.JsonSlurper

def json = new JsonSlurper()
def conf = json.parse(new File(args[0])).installed

def code = args[1]

def param = { name, value -> new BasicNameValuePair(name, value) }

def client = HttpClientBuilder.create().build()

def post = new HttpPost('https://www.googleapis.com/oauth2/v3/token')

post.entity = new UrlEncodedFormEntity([
    param('code', code),
    param('client_id', conf.client_id),
    param('client_secret', conf.client_secret),
    param('grant_type', 'authorization_code'),
    param('redirect_uri', conf.redirect_uris[0]) //urn:ietf:wg:oauth:2.0:oob
])

def res = client.execute(post)

// 実行結果(JSON)の出力
res.entity.writeTo(System.out)

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

実行例
> groovy get_refresh-token.groovy client_secret.json 4/3vJ9・・・ > token.json

成功すると以下のような JSON を取得できます。

処理結果
{
 "access_token": "・・・",
 "token_type": "Bearer",
 "expires_in": 3600,
 "refresh_token": "・・・"
}

(4) アクセストークンの取得と Gmail API 利用

最後に GmailAPI を使ってメールの情報を取得してみます。

ここでは以下のモジュールを使いました。

リフレッシュトークンを GoogleCredentialsetRefreshToken で設定しておけばアクセストークンを自動的に取得して処理してくれるようです。

gmail_list.groovy
@Grab('com.google.apis:google-api-services-gmail:v1-rev31-1.20.0')
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.googleapis.util.Utils
import com.google.api.services.gmail.Gmail

import groovy.json.JsonSlurper

def json = new JsonSlurper()

def conf = json.parse(new File(args[0])).installed
def token = json.parse(new File(args[1]))

def credential = new GoogleCredential.Builder()
    .setTransport(Utils.getDefaultTransport())
    .setJsonFactory(Utils.getDefaultJsonFactory())
    .setClientSecrets(conf.client_id, conf.client_secret)
    .build()
    .setRefreshToken(token.refresh_token) //リフレッシュトークンの設定

def gmail = new Gmail.Builder(
    Utils.getDefaultTransport(), 
    Utils.getDefaultJsonFactory(), 
    credential
).setApplicationName('sample').build()

// メールの情報を最大 3件取得
gmail.users().messages().list('me').setMaxResults(3).execute().messages.each {
    // メールの内容を minimal フォーマットで取得
    def msg = gmail.users().messages().get('me', it.id).setFormat('minimal').execute()
    println msg
}

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

実行例
> groovy gmail_list.groovy client_secret.json token.json

[historyId:1000, ・・・ snippet:詳細な管理によって Google アカウントを保護・・・]
・・・