C#エンジニアのためのBigQuery入門(番外編)
Google API Client Library for .NETの使い方
BigQueryをはじめ、GoogleのほとんどのサービスはAPIが提供されている。これを.NETから利用するためのライブラリの基本的な使用方法を解説する。
Google API Client Library for .NETとは
本連載で紹介しているBigQueryをはじめとして、グーグルはさまざまなサービスを提供している。BigQueryやCloud Storageは比較的最近リリースされたGoogle Cloud Platformのサービスであり、GmailやGoogle CalendarといったGoogle Appsサービスといった幅広いサービスに対しグーグルはAPIを公開しており、開発者が利用できるようになっている。APIはHTTP通信を利用するため多くののプログラミング言語で利用可能であるが、開発者がよりシンプルかつ柔軟にAPIを利用できるように、Google API Client Libraryとして、いくつかの言語向けにクライアントライブラリを提供している。その中にGoogle API Client Library for .NETという.NET Framework向けのライブラリも含まれており、NuGetからダウンロードして利用可能になっている。
BigQueryのAPIもClient Library for .NETの一つとして提供されているが、(BigQueryに限らず)Client Libraryを利用するためのユーザー認証方法が何種類か用意されていることもあり、そのAPIの使用方法はやや煩雑である。そこで今回は、BigQuery APIも含め、Google API Client Library for .NETを利用する方法を、ユーザーの認証情報を中心に説明したい。
Google Developer ConsoleからAPIを利用可能にする
まず、APIを利用可能にするためにGoogleアカウントで認証した状態でGoogle Developer Consoleにアクセスする。プロジェクトを作成していればプロジェクト一覧が表示され、まだ作成していなければ作成画面が表示される。
今回は「APITest」というプロジェクトを新規に作成した。プロジェクト作成の詳細は、連載第1回も参考にしてほしい。プロジェクトを作成、あるいは選択後に表示されるページで、左側のペインから[APIと認証]を開き、[API]を選択してほしい。API一覧が表示されるはずだ(図1)。
多くのAPIはデフォルトで無効の状態になっており、このコンソールで有効にしないと利用できない。右側の検索欄に「URL Shortener」と入力し、[URL Shortener API]のリンクをクリックしてほしい。[API を有効にする]というボタンが表示されるはずだ(図2)。
[API を有効にする]ボタンが表示されているときは無効な状態であるので、これを押すと有効にできる。有効にしたら、左側のペインで[認証情報]を選択してほしい(図3)。
この画面で、いわゆる認証キーを発行し、API利用時にその値をセットすることになる。この認証情報はプロジェクト全体を通して有効になるため、複数のAPIを有効にした場合、同じ認証情報で認証できる。なお、後述するようにAPIを利用する場合に、スコープと呼ばれるAPIの利用可能な範囲を指定することになる。
さて、この図3の画面では[OAuth]と[公開 API へのアクセス]という2種類のボタンが用意されている。それぞれの方法に分けて説明しよう。
APIキーとOAuth 2.0による2種類の認証方法
Google APIの利用には認証が必要である。これは課金や上限の管理のためにAPIを実行しているアプリケーションを識別するためである。そして、その認証方法は「APIキーによる公開APIへのアクセス」と「OAuth 2.0による認証」の2つに大きく分かれる。さらに、Googleアカウント内のプライベートな情報にアクセスする場合には認可が必要であり、この場合はOAuth 2.0による認可が必要になる。Googleのドキュメントは英語だが、認証が「Authentication」、認可が「Authorization」に当たる。
APIキーによる公開APIへのアクセス
APIキーによるアクセスでは、上に書いた通り、公開されている情報だけにアクセスするAPIのみ利用可能である。そこでここでは図2で有効にした「URL shortener API」を例にして、これを試してみよう。
APIキーの作成と取得
図3の状態で、[公開 API へのアクセス]の下にある[新しいキーを作成]ボタンを押す。図4のように選択肢が出てくるので、ここでは[サーバー キー]を選択する。
次に、図5のように許可対象IPアドレスの設定の画面に移る。実際に運用する場合は、自分の管理外のコンピューターから実行されるのを防ぐために、実行するマシンがGoogleにアクセスする場合のIPアドレスを指定した方がよいが、今回はテスト実行であるため何も指定しないまま[作成]ボタンを押し、全てのIPからの実行を許可した状態にする。
すると、図6のように元の認証情報画面に作成されたAPIキーの情報が表示される。
では、このAPIキーを使ってアクセスしてみよう。
公開APIへのアクセス
Visual Studioでコンソールプロジェクトを作成し、Google URL Shortener API用のライブラリをNuGetから参照に追加する。
Install-Package Google.Apis.Urlshortener.v1
|
ライブラリを追加したら、以下のようにコードを書いて実行してほしい。ApiKey
プロパティには先ほど作成したAPIキーを指定してほしい。
using Google.Apis.Urlshortener.v1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var shortener = new UrlshortenerService(
new Google.Apis.Services.BaseClientService.Initializer
{
ApiKey = "(作成したAPIキー)"
});
var shorten = shortener.Url.Insert(new Google.Apis.Urlshortener.v1.Data.Url
{
LongUrl = "http://tanaka733.net"
}).Execute();
Console.WriteLine("短縮したURL {0}", shorten.Id);
var url = shortener.Url.Get(shorten.Id).Execute();
Console.WriteLine("復元した元のURL {0}", url.LongUrl);
Console.ReadLine();
}
}
}
|
Google APIは、まず<API名>Service
(この例ではUrlshortenerService
)というクラス名のインスタンスを作成するところから始まる。このコンストラクターの引数に認証情報を渡すのだが、APIキーの場合はGoogle.Apis.Services
名前空間に所属するBaseClientService.Initializer
クラス・インスタンスのAPIKey
プロパティに渡せばよい。
次にこのサービス(例ではUrlshortenerService
オブジェクト)からAPIを実行するが、サービスの下にリソースごとにプロパティ(Google URL Shortenerの場合はUrl
プロパティ)を持っており、さらにプロパティの下にアクション(URLというリソースに対するGet
やInsert
など)に対応したメソッドが用意されている。アクションに対応したメソッドの返り値はAPIリクエストに対応しており、返り値に対してExecute
メソッドもしくは非同期のExecuteAsync
メソッドを実行することで、APIリクエストを実行し、レスポンスを取得できる。この大まかな構造は、どのAPIにおいても同じである。
実行すると、図7のようにコンソールにURLの短縮/復元の結果が表示されるはずだ。短縮したURLの部分をコピーして、ブラウザーで開くと元のURLにリダイレクトされることも確認できる。
このサンプルはコンソールアプリとして実行したが、ASP.NET MVCなどのサーバーサイドで動く場合もほぼ同様に実行できる。また、ユニバーサルWindowsアプリ(Windows 8.1向け)の場合もほぼ同様に実行できる(Google API Client Library側でプラットフォームの差分を吸収しているので、同じ名前でNuGetから追加すればよい)。ただ、本稿執筆時点ではWindows 10向けのユニバーサルWindowsアプリには対応できていないようである。
OAuth 2.0によるAPIアクセス
次にOAuth 2.0によるアクセスと認可の方法について説明する。認可が必要なAPIの例としてGoogle+ APIを利用する。
「サービスアカウント」のクライアントIDの作成と取得
図1と同じ方法で左側のペインで「API」を選び、今度は「Google+」と入力し、[Google+ API]リンクをクリックしてAPIを有効にしてほしい。
有効にしたら、[認証情報]に戻り、[OAuth]の下の[新しいクライアント ID を作成する]ボタンをクリックし、出てくる選択肢で[サービス アカウント]を選択してほしい(図9)。
3つの選択肢のうち[サービス アカウント]のみ、他の2つと異なる使い方をする。認可が必要なAPIではあるが、ユーザーの個人情報にアクセスせずに実行する場合、サービスアカウントという特別なアカウント情報を使ってアクセスできる。本連載で扱っているBigQuery APIもこの例であり、BigQueryを管理しているユーザーの個人情報にはアクセスしないため、サービスアカウントとして利用できる。Google+ APIの例で言うと、公開ユーザーの情報や公開されているActivityへのアクセスが、このサービスアカウントで利用可能である。
残り2つの選択肢は、アプリケーションが、Googleアカウントで認証されたユーザーに、そのユーザー個人の情報へのアクセスの許可を求めるものになる。Google+でいえば、そのユーザー自身の情報にアクセスしたり、そのユーザーとして投稿したりすることに当たる。
まずはサービスアカウントでの利用方法についての説明を進めよう。図9の状態で[クライアント ID を作成]ボタンを押すと、元の認証情報ページに戻り、クライアントIDが作成され(図10)、.json
という拡張子のファイルがブラウザーでダウンロードされているだろう。
この.jsonファイルは認証鍵として利用するのだが、本稿執筆時点のClient APIのバージョン1.9.0
ではJSONファイルによるテキストベースの認証はサポートしていない。そのため、図10に示す[新しい P12 キーを生成]ボタンを押し、p12証明書を作成し、ダウンロードする。このとき、パスワードが表示されるため、そのパスワードを念のため保存しておく。現時点では、このパスワードはどのGoogleアカウントでどんなサービスアカウントを作成しても同一文字列のようである。
.jsonファイルのテキストベースの認証鍵とp12証明書の違いだが、.NET Frameworkにおいては、X509Certificate2
クラスでp12証明書を扱う一部APIは、ユーザープロファイル空間が存在していなければいけない、という考慮が必要な点である。ログインした状態でコンソールアプリを起動する場合はあまり気にすることはないが、ASP.NETなWebアプリで利用したり、Windowsサービスの中で利用したりする場合にはユーザープロファイル空間が存在しているか考慮する必要があるだろう。
それではこの証明書とクライアントIDを使って認証してみよう。
「サービスアカウント」によるAPIアクセス
コンソールアプリにNuGetで、Google+ APIを追加する。
Install-Package Google.Apis.Plus.v1
|
追加したら以下のコードの、(図10に表示されている)サービスアカウントのメールアドレス、証明書のパスとパスワードを自分の環境に合わせて記入して実行してほしい。
using Google.Apis.Auth.OAuth2;
using Google.Apis.Plus.v1;
using Google.Apis.Services;
using System;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var serviceAccountEmail = "(サービスアカウントのメールアドレス)";
var certificate = new X509Certificate2(@"(p12証明書のパス)", "(p12証明書作成時に表示されたパスワード)", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] {
PlusService.Scope.PlusMe,
PlusService.Scope.PlusLogin,
PlusService.Scope.UserinfoEmail,
PlusService.Scope.UserinfoProfile
}
}.FromCertificate(certificate));
var service = new PlusService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "APITest",
});
var person = service.People.Get("+google").Execute();
Console.WriteLine(person.DisplayName);
Console.ReadLine();
}
}
}
|
Google+公式アカウントの情報を取得している。
証明書を指定してServiceAccountCredential
オブジェクトを作成し、これをInitializer
経由でPlusService
クラスのコンストラクターに渡している。APIの実行はPeople
というリソースにGet
というアクションを実行しているのが分かるだろう。
「インストールアプリ」のクライアントIDの作成と取得
続いて、残り2つのクライアントIDによるAPIアクセス方法の説明に移りたいが、残り2つはクライアントIDを作成しようとすると、図11のように[同意画面を設定]という警告が表示される。これは、ユーザーに表示する同意画面の設定が必要なためである。このボタンを押すか、左側のペインで[同意画面]を押す。どちらを行っても、図12に示す同意画面の設定ページに移動する。
同意画面の設定(図12)を行うには、最低限メールアドレスの選択とサービス名(この例では「API Test」)を入力する必要がある。本番運用する場合、このメールアドレスはアプリケーションでエラーが起きたときなどに、グーグルがアプリケーション利用者に対して管理者の連絡先として表示するなどされるため、公開されても問題ないメールアドレスにしておくのが好ましい。また、利用者に対して十分な情報が提供できるように、任意入力の項目についても入力することを検討してほしい。
※メールアドレスはマスキングしている。
それでは、クライアントIDの作成画面に戻って、[インストールされているアプリケーション]を選択してみよう。図13に示すように、いくつかデバイスの種類が表示されるが、[その他]を選択すれば、Windowsデスクトップ、Windows 8.1向けユニバーサルWindowsアプリなどで利用できる。
すると図14のように、作成されたクライアントIDの情報が表示されるはずである。ここで、[JSON をダウンロード]をクリックし、.jsonファイルをダウンロードしてほしい。
「インストールアプリ」によるAPIアクセス
そして、先ほどと同様にGoogle.Apis.Plus.v1ライブラリが追加された状態で、以下のコードを実行する。今度は、ダウンロードした.jsonファイルのパスを自分の環境に合わせて指定するのと、最後のユーザー情報の取得がGoogle+公式アカウントではなく、「me」と指定して認証されたユーザー自身の情報の取得になっている点に注意してほしい。
using Google.Apis.Auth.OAuth2;
using Google.Apis.Plus.v1;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
UserCredential credential;
using (var stream = new FileStream("(ダウンロードした.jsonファイルのパス)", FileMode.Open, FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] {
PlusService.Scope.PlusMe,
PlusService.Scope.PlusLogin,
PlusService.Scope.UserinfoEmail,
PlusService.Scope.UserinfoProfile
},
"user", CancellationToken.None, new FileDataStore("Api.Plus.Store")).Result;
}
var service = new PlusService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "APITest",
});
var person = service.People.Get("me").Execute();
Console.WriteLine(person.DisplayName);
Console.ReadLine();
}
}
}
|
ログインしたユーザー自身の情報を取得している。
このコードを実行すると、ブラウザーが起動し、図15のような画面が開くはずだ。Googleアカウントでのログインが求められた場合は、自分のアカウントでログインすると、この画面に移動する。
これが、OAuthでいう、ユーザーに対してアプリケーションが情報の取得や操作を一定の範囲内で許可することの同意を求める画面である。表示されている許可一覧はAuthorizeAsync
メソッドで渡しているScope
の配列に対応している。この画面で[承認する]を選ぶと、ログインしたユーザーの表示名(=DisplayName
プロパティ)がコンソールに表示されるはずである。なお、[キャンセル]を押した場合の処理は想定していないコードになっているが、運用するアプリケーションとしては、キャンセル時の考慮も必要である。
「Webアプリ」のクライアントIDの作成と取得
最後に、Webアプリ向けのクライアントIDを使う場合について説明する。ASP.NET MVCアプリケーションで、WebアプリがOAuthの認可を求め、ユーザーの認証情報でGoogle APIを実行する方法である。
この認証フローを実行するためには、ユーザーが認可リクエストを承認した後に、グーグルからアプリケーションにCallbackしてもらうWebアプリのドメインとパスを指定する必要がある。今回はAzure Web Apps(旧Azure Websites)にアプリケーションをホスティングする前提で説明をする。
左側のペインで[認証情報]に戻り、[OAuth]の下の[新しいクライアント ID を作成する]ボタンをクリックし、出てくる選択肢で[ウェブ アプリケーション]を選択してほしい。すると、[承認済みの JavaScript 生成元]と[承認済みのリダイレクト URL]の入力が求められるので、それぞれ「Webアプリのドメイン名(図16の例ではhttps://googleapisample.azurewebsites.net
」「Webアプリのドメイン名/AuthCallback/IndexAsync」を指定してほしい。「AuthCallback/IndexAsync」というパスは、以下の説明で利用するライブラリが利用するデフォルトのパスである。
クライアントIDを作成すると、図17のように作成されたIDが表示されるはずだ。
では、Webアプリケーションで記述するコードの説明に移ろう。
「Webアプリ」によるAPIアクセス
Visual Studioで作成したASP.NET MVCアプリケーション(本稿の例では「GoogleApiSample」というプロジェクト名にした)に、利用するGoogle APIのライブラリ(今回は「Google.Apis.Plus.v1」)に加え、「Google.Apis.Auth.MVC」をインストールする。
Install-Package Google.Apis.Plus.v1
Install-Package Google.Apis.Auth.MVC
|
続いてFlowMetadata
クラス(Google.Apis.Auth.OAuth2.Mvc
名前空間)を継承したAppFlowMetadata
クラスを作成する。このクラスには、先ほど作成したクライアントIDとクライアントシークレット、アプリが利用するスコープを定義する他、このサンプルでは単純化しているが、FileDataStore
ではなく適宜DBに保存するためのDataStoreの指定や、セッションではなくOpenID Connectを利用したユーザーIDの生成および保管のロジックを記述することもできる。
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Plus.v1;
using Google.Apis.Util.Store;
using System;
using System.Web.Mvc;
namespace GoogleApiSample
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "(作成したクライアントID)",
ClientSecret = "(作成したクライアントシークレット)"
},
Scopes = new[] {
PlusService.Scope.PlusMe,
PlusService.Scope.PlusLogin,
PlusService.Scope.UserinfoEmail,
PlusService.Scope.UserinfoProfile
},
DataStore = new FileDataStore("Plus.Api.Auth.Store")
});
public override string GetUserId(Controller controller)
{
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
}
|
次に、HomeController
を作成して、「/Home/Index」にアクセスしたら、OAuthの認可があるかどうかを確認し、なければ認可フローを実行し、存在すればGoogle APIを利用するコードを記述する。これもサンプルのため、HomeController
クラスに記述しているが、適宜、Filterに記述するなど再利用しやすい形式にすることもできるだろう。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Plus.v1;
using Google.Apis.Services;
namespace GoogleApiSample.Controllers
{
public class HomeController : Controller
{
public async Task<ActionResult> Index(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata())
.AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
try
{
var service = new PlusService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "ASP.NET MVC Sample"
});
var me = await service.People.Get("me").ExecuteAsync(cancellationToken);
ViewBag.Message = "Welcome: " + me.DisplayName;
return View();
}
catch(Exception e)
{
ViewBag.Exception = e;
return View();
}
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
}
}
|
ViewBag.Message
に実行したAPIの結果を格納している。
これを表示するViewの.cshtmlファイルは、非常に単純なサンプルとしてこの値だけを表示するようにした。
<div>@ViewBag.Message</div>
|
HomeControllerのIndexメソッドに対応するViewとなるよう、「Views/Home」フォルダの下に保存する。
最後に、OAuthフローのCallBackを受け取るAuthCallbackController
を記述する。
using Google.Apis.Auth.OAuth2.Mvc;
namespace GoogleApiSample.Controllers
{
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected override FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
}
}
|
ここまで記述したら、Azure Web Appsにデプロイして、httpsでAzure Web Appsにアクセスしてほしい。Googleアカウントで認証していれば、図15と同様のOAuthの認可確認画面が表示され、承認すればAPIの実行結果(認証しているGoogleユーザーのDisplayName
)が表示されるはずだ。
■
以上、Google API Client Library for .NETの認証方法についてまとめて説明してきた。BigQuery連載の第2回からは実際にAPIを実行してみるが、今回の認証方法で出てきた「サービスアカウントによる認証」を主に利用していく予定である。
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. 誰でも簡単に超高速なクエリができるBigQueryとは?
知らないと損! 使わないと損! これからのデータ解析に必須のBigQueryの概要を紹介。また、Webコンソールからのクエリ実行の基礎を解説する。
2. 【現在、表示中】≫ Google API Client Library for .NETの使い方
BigQueryをはじめ、GoogleのほとんどのサービスはAPIが提供されている。これを.NETから利用するためのライブラリの基本的な使用方法を解説する。
5. LINQでBigQuery: データスキャン量を抑えたクエリの実行方法
膨大なデータへのクエリで、スキャン量を減らしてクエリの課金額を抑えるには? テーブルワイルドカード関数とテーブルデコレーターを説明する。