このドキュメントでは、OAuth 2.0 の概要、それを使用するタイミング、クライアント ID の取得方法、.NET 用 Google API クライアント ライブラリで使用する方法について説明します。
OAuth 2.0 プロトコル
OAuth 2.0 は Google API で使用される認証プロトコルです。このプロトコルについて理解するには、次のリンクをご覧ください。
クライアント ID とクライアント シークレットの取得
クライアント ID とクライアント シークレットは Google API Console で取得できます。クライアント ID にはさまざまなタイプがあるため、アプリケーションに適したタイプを取得してください。
- ウェブ アプリケーションのクライアント ID
- インストール済みアプリケーションのクライアント ID
- サービス アカウントのクライアント ID
以下の各コード スニペット(サービス アカウント 1 を除く)では、クライアント シークレットをダウンロードし、プロジェクトに client_secrets.json
として保存する必要があります。
クルデンシャル
ユーザー認証情報
UserCredential
は、アクセス トークンを使用して保護されたリソースにアクセスするためのスレッドセーフなヘルパークラスです。アクセス トークンは通常 1 時間後に期限切れになります。その後、アクセス トークンを使用しようとすると、エラーが発生します。
UserCredential
と AuthorizationCodeFlow
は、トークンを自動的に「更新」します。これは、単に新しいアクセス トークンを取得することを意味します。認可コードフローで access_type=offline
パラメータを使用する場合は、有効期間の長い更新トークンをアクセス トークンとともに受け取ります。
ほとんどのアプリケーションでは、認証情報のアクセス トークンと更新トークンを永続ストレージに保存することをおすすめします。それ以外の場合は、アクセス トークンは受信後 1 時間で有効期限が切れるため、1 時間ごとにブラウザで認証ページをエンドユーザーに表示する必要があります。
アクセス トークンと更新トークンを確実に維持するには、IDataStore
の独自の実装を提供するか、ライブラリから提供される次のいずれかの実装を使用します。
-
.NET 用の
FileDataStore
を使用すると、認証情報がファイル内で永続的になります。
ServiceAccountCredential
ServiceAccountCredential
は UserCredential
に似ていますが、別の目的を果たします。Google OAuth 2.0 は、ウェブ アプリケーションと Google Cloud Storage の間のようなサーバー間インタラクションをサポートしています。リクエスト元のアプリケーションが API にアクセスするには、自身の ID を証明する必要があり、エンドユーザーの関与は必要ありません。
ServiceAccountCredential
には秘密鍵が格納されます。これは、新しいアクセス トークンを取得するリクエストに署名するために使用されます。
UserCredential
と ServiceAccountCredential
はどちらも IConfigurableHttpClientInitializer
を実装しているため、それぞれを以下のように登録できます。
- 失敗したレスポンス ハンドラ。HTTP
401
ステータス コードを受け取った場合はトークンを更新します。 - すべてのリクエストで
Authorization
ヘッダーをインターセプトするインターセプタ。
インストール型アプリケーション
Books API を使用したサンプルコード:
using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; using Google.Apis.Books.v1; using Google.Apis.Books.v1.Data; using Google.Apis.Services; using Google.Apis.Util.Store; namespace Books.ListMyLibrary { /// <summary> /// Sample which demonstrates how to use the Books API. /// https://developers.google.com/books/docs/v1/getting_started /// <summary> internal class Program { [STAThread] static void Main(string[] args) { Console.WriteLine("Books API Sample: List MyLibrary"); Console.WriteLine("================================"); try { new Program().Run().Wait(); } catch (AggregateException ex) { foreach (var e in ex.InnerExceptions) { Console.WriteLine("ERROR: " + e.Message); } } Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } private async Task Run() { UserCredential credential; using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)) { credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, new[] { BooksService.Scope.Books }, "user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary")); } // Create the service. var service = new BooksService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "Books API Sample", }); var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync(); ... } } }
-
このサンプルコードでは、
GoogleWebAuthorizationBroker.AuthorizeAsync
メソッドを呼び出して、新しいUserCredential
インスタンスを作成します。この静的メソッドは以下を取得します。- クライアント シークレット(またはクライアント シークレットへのストリーム)。
- 必要なスコープ。
- ユーザー ID。
- オペレーションをキャンセルするためのキャンセル トークン。
- オプションのデータストア。データストアが指定されていない場合、デフォルトは、デフォルトの
Google.Apis.Auth
フォルダがあるFileDataStore
です。フォルダはEnvironment.SpecialFolder.ApplicationData
に作成されます。
-
このメソッドによって返される
UserCredential
は、(イニシャライザを使用して)BooksService
でHttpClientInitializer
として設定されます。前述のように、UserCredential
は HTTP クライアント イニシャライザを実装します。 -
上記のサンプルコードでは、クライアント シークレット情報がファイルから読み込まれていますが、次のことも可能です。
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( new ClientSecrets { ClientId = "PUT_CLIENT_ID_HERE", ClientSecret = "PUT_CLIENT_SECRETS_HERE" }, new[] { BooksService.Scope.Books }, "user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
Books のサンプルをご覧ください。
ウェブ アプリケーション(ASP.NET Core 3)
Google API は、 ウェブサーバー アプリケーション用の OAuth 2.0 をサポートしています。
Google.Apis.Auth.AspNetCore3 は、ASP.NET Core 3 アプリケーションでほとんどの Google ベースの OAuth 2.0 シナリオで使用する場合に推奨されるライブラリです。Google 固有の OpenIdConnect
認証ハンドラを実装しています。増分認証をサポートし、Google API で使用できる Google 認証情報を提供するために挿入可能な IGoogleAuthProvider
を定義します。
このセクションでは、Google.Apis.Auth.AspNetCore3 を構成して使用する方法について説明します。ここに示すコードは、完全に機能する標準 ASP.NET Core 3 アプリケーションである Google.Apis.Auth.AspNetCore3.IntegrationTests に基づいています。
このドキュメントをチュートリアルとして参照する場合は、独自の ASP.NET Core 3 アプリケーションが必要です。また、前提条件として以下の手順も完了する必要があります。
Prerequisites
- Google.Apis.Auth.AspNetCore3 パッケージをインストールします。
- Google Drive API を使用しているため、Google.Apis.Drive.v3 パッケージもインストールする必要があります。
- Google Cloud プロジェクトを作成します(まだ作成していない場合)。 こちらの手順に沿って操作してください。これが、アプリの識別に使用されるプロジェクトになります。
- Google Drive API を有効にします。API を有効にするには、 こちらの手順に沿って操作してください。
-
Google に対してアプリを識別するための認証情報を作成します。
こちらの手順に沿って認証情報を作成し、
client_secrets.json
ファイルをダウンロードします。2 つのポイントがあります。- 認証情報のタイプは [ウェブ アプリケーション] である必要があります。
- このアプリを実行する場合、追加する必要があるリダイレクト URI は
https://localhost:5001/signin-oidc
のみです。
Google.Apis.Auth.AspNetCore3 を使用するようにアプリケーションを構成する
Google.Apis.Auth.AspNetCore3 は、Startup
クラスまたは使用している同様の代替手段で構成されます。次のスニペットは、Google.Apis.Auth.AspNetCore3.IntegrationTests プロジェクトの
Startup.cs
から抽出されたものです。
-
Startup.cs
ファイルに次の using ディレクティブを追加します。using Google.Apis.Auth.AspNetCore3;
-
Startup.ConfigureServices
メソッドに次のコードを追加し、クライアント ID とクライアント シークレットのプレースホルダをclient_secrets.json
ファイルに含まれる値に変更します。これらの値は、JSON ファイルから直接読み込むことも、他の安全な方法で保存することもできます。これらの値を JSON ファイルから直接読み込む方法については、Google.Apis.Auth.AspNetCore3.IntegrationTests プロジェクトのClientInfo.Load
メソッドをご覧ください。public void ConfigureServices(IServiceCollection services) { ... // This configures Google.Apis.Auth.AspNetCore3 for use in this app. services .AddAuthentication(o => { // This forces challenge results to be handled by Google OpenID Handler, so there's no // need to add an AccountController that emits challenges for Login. o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme; // This forces forbid results to be handled by Google OpenID Handler, which checks if // extra scopes are required and does automatic incremental auth. o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme; // Default scheme that will handle everything else. // Once a user is authenticated, the OAuth2 token info is stored in cookies. o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie() .AddGoogleOpenIdConnect(options => { options.ClientId = {YOUR_CLIENT_ID}; options.ClientSecret = {YOUR_CLIENT_SECRET}; }); }
-
Startup.Configure
メソッドで、必ず ASP.NET Core 3 認証および認可ミドルウェア コンポーネントと、HTTPS リダイレクトをパイプラインに追加します。public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
ユーザーの認証情報を使用して、ユーザーに代わって Google API にアクセスする
これで、Google API にアクセスするためのユーザー認証情報を必要とするアクション メソッドをコントローラに追加できるようになりました。次のスニペットは、認証されたユーザーの Google ドライブ アカウントにあるファイルを一覧表示する方法を示しています。主に次の 2 点に注目してください。
-
ユーザーを認証する必要があるだけでなく、
https://www.googleapis.com/auth/drive.readonly
スコープをアプリに付与する必要もあります。スコープはGoogleScopedAuthorize
属性で指定します。 -
ここでは、ユーザーの認証情報の取得に使用する
IGoogleAuthProvider
を受け取るために、ASP.NET Core 3 の標準の依存関係インジェクション メカニズムを使用しています。
コードは次のようになります。
-
まず、次の using ディレクティブをコントローラに追加します。
using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;
-
次のように、コントローラ アクションを追加します(
IList<string>
モデルを受け取るシンプルなビューを添えてください)。/// <summary> /// Lists the authenticated user's Google Drive files. /// Specifying the <see cref="GoogleScopedAuthorizeAttribute"> will guarantee that the code /// executes only if the user is authenticated and has granted the scope specified in the attribute /// to this application. /// </summary> /// <param name="auth">The Google authorization provider. /// This can also be injected on the controller constructor.</param> [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)] public async Task<IActionResult> DriveFileList([FromServices] IGoogleAuthProvider auth) { GoogleCredential cred = await auth.GetCredentialAsync(); var service = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = cred }); var files = await service.Files.List().ExecuteAsync(); var fileNames = files.Files.Select(x => x.Name).ToList(); return View(fileNames); }
これらは基本的なことです。以下の方法については、Google.Apis.Auth.AspNetCore3.IntegrationTests プロジェクトの
HomeController.cs
をご覧ください。
- ユーザー認証のみ、特定のスコープなし
- ログアウト機能
- コードによる段階的な認証。上記のスニペットでは、属性による増分承認が示されています。
- 現在付与されているスコープを調べる
- アクセス トークンと更新トークンを調べる
- アクセス トークンを強制的に更新します。この操作は自分で行う必要はありません。Google.Apis.Auth.AspNetCore3 は、アクセス トークンの有効期限が切れているか有効期限が近づいているかを検出し、自動的に更新します。
サービス アカウント
Google API は、サービス アカウントもサポートしています。クライアント アプリケーションがエンドユーザーのデータへのアクセスをリクエストするシナリオとは異なり、サービス アカウントはクライアント アプリケーション自体のデータへのアクセスを提供します。
クライアント アプリケーションは、Google API Console からダウンロードした秘密鍵を使用して、アクセス トークンのリクエストに署名します。新しいクライアント ID を作成したら、アプリケーション タイプに [サービス アカウント] を選択します。その後、秘密鍵をダウンロードできます。 Google Plus API を使用したサービス アカウントのサンプルをご覧ください。
using System; using System.Security.Cryptography.X509Certificates; using Google.Apis.Auth.OAuth2; using Google.Apis.Plus.v1; using Google.Apis.Plus.v1.Data; using Google.Apis.Services; namespace Google.Apis.Samples.PlusServiceAccount { /// <summary> /// This sample demonstrates the simplest use case for a Service Account service. /// The certificate needs to be downloaded from the Google API Console /// <see cref="https://console.cloud.google.com/"> /// "Create another client ID..." -> "Service Account" -> Download the certificate, /// rename it as "key.p12" and add it to the project. Don't forget to change the Build action /// to "Content" and the Copy to Output Directory to "Copy if newer". /// </summary> public class Program { // A known public activity. private static String ACTIVITY_ID = "z12gtjhq3qn2xxl2o224exwiqruvtda0i"; public static void Main(string[] args) { Console.WriteLine("Plus API - Service Account"); Console.WriteLine("=========================="); String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE"; var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable); ServiceAccountCredential credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail) { Scopes = new[] { PlusService.Scope.PlusMe } }.FromCertificate(certificate)); // Create the service. var service = new PlusService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "Plus API Sample", }); Activity activity = service.Activities.Get(ACTIVITY_ID).Execute(); Console.WriteLine(" Activity: " + activity.Object.Content); Console.WriteLine(" Video: " + activity.Object.Attachments[0].Url); Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } } }
上記のサンプルコードでは、ServiceAccountCredential
を作成します。必要なスコープが設定され、FromCertificate
が呼び出され、指定された X509Certificate2
から秘密鍵が読み込まれます。他のサンプルコードと同様に、認証情報は HttpClientInitializer
として設定されています。