本文件說明 OAuth 2.0 及其使用時機、取得用戶端 ID 的方式,以及如何將用戶端 ID 與 Google 專用 Google API 用戶端程式庫搭配使用。
OAuth 2.0 通訊協定
OAuth 2.0 是 Google API 使用的授權通訊協定。 建議您詳閱下列連結,以熟悉通訊協定:
取得用戶端 ID 與密鑰
您可以在 Google API 控制台中取得用戶端 ID 和密鑰。用戶端 ID 類型不同,因此請務必為應用程式取得正確的類型:
在以下各個程式碼片段 (服務帳戶 1 除外) 中,您必須下載用戶端密鑰,並儲存在專案中為 client_secrets.json
。
憑證
使用者憑證
UserCredential
是對執行緒安全的輔助類別,會使用存取權杖來存取受保護的資源。存取權杖通常會在 1 小時後過期,如果之後嘗試使用該權杖,就會收到錯誤訊息。
UserCredential
和 AuthorizationCodeFlow
會自動處理「重新整理」權杖,權杖只是取得新的存取權杖。方法是使用長效重新整理權杖,如果您在授權碼流程中使用 access_type=offline
參數,就會一併收到存取權杖。
在大部分的應用程式中,建議將憑證的存取權杖和重新整理權杖儲存在永久儲存空間中。否則,您就必須每小時向使用者在瀏覽器中顯示授權頁面,因為存取權杖會在您收到要求後的一小時後過期。
為了確保存取權和更新權杖保持不變,您可以提供自己的 IDataStore
實作,也可以使用程式庫提供的下列其中一個實作項目:
-
.NET 的
FileDataStore
可確保憑證永久有效,
ServiceAccountCredential
ServiceAccountCredential
與 UserCredential
類似,但其用途不同。
Google OAuth 2.0 支援伺服器對伺服器的互動,例如網頁應用程式和 Google Cloud Storage 之間的互動。提出要求的應用程式必須證明自己的身分,才能存取 API;使用者不必參與其中。
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。
- 用於取消作業的取消權杖。
- 選用的資料儲存庫。如未指定資料儲存區,則預設值為
FileDataStore
和預設的Google.Apis.Auth
資料夾。系統會在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"));
查看圖書範例。
網頁應用程式 (ASP.NET Core 3)
Google API 支援網路伺服器應用程式適用的 OAuth 2.0。
對於 ASP.NET Core 3 應用程式中的大多數 Google 提供的 OAuth 2.0 情境,建議您使用 Google.Apis.Auth.AspNetCore3 這個程式庫。其導入 Google 專屬的 OpenIdConnect
驗證處理常式。其支援漸進式驗證機制,並定義可插入的 IGoogleAuthProvider
,以提供可與 Google API 搭配使用的 Google 憑證。
本節說明如何設定及使用 Google.Apis.Auth.AspNetCore3。此處顯示的程式碼以 Google.Apis.Auth.AspNetCore3.IntegrationTests 為基礎,後者是完全有效的標準 ASP.NET Core 3 應用程式。
如要以這份說明文件做為教學課程,您必須使用自己的 ASP.NET Core 3 應用程式,並完成這些步驟。
必要條件
- 安裝 Google.Apis.Auth.AspNetCore3 套件。
- 我們目前採用 Google Drive API,因此您也必須安裝 Google.Apis.Drive.v3 套件。
- 如果您還沒有 Google Cloud 專案,請先建立。請按照這裡的操作說明操作。這是應用程式會識別的專案。
- 請務必啟用 Google Drive API。如要啟用 API,請按照這些操作說明操作。
-
建立授權憑證,向 Google 識別您的應用程式。請按照這些操作說明建立授權憑證,並下載
client_secrets.json
檔案。有兩個重點:- 請注意,憑證' 類型必須為「網頁應用程式」。
- 如要執行這個應用程式,您需要新增的重新導向 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 Google.Apis.Auth.AspNetCore3;
-
在
Startup.ConfigureServices
方法中新增下列程式碼,將用戶端 ID 和用戶端密鑰預留位置替換為client_secrets.json
中包含的值。您可以直接從 JSON 檔案載入這些值,或是透過其他安全方式儲存這些值。查看 Google.Apis.Auth.AspNetCore3.IntegrationTests 專案中的ClientInfo.Load
方法,瞭解如何直接從 JSON 檔案載入這些值。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 雲端硬碟帳戶中列出檔案。請留意兩個重點:
-
使用者不僅需要進行驗證,也需要將應用程式的
https://www.googleapis.com/auth/drive.readonly
範圍授權給您透過GoogleScopedAuthorize
屬性指定的應用程式。 -
我們使用 ASP.NET Core 3' 的標準依附元件插入機制取得
IGoogleAuthProvider
,以便用來取得使用者憑證。
程式碼:
-
首先,請使用控制器指令新增以下內容。
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 會偵測存取權杖是否過期或即將過期,並自動重新整理。
網頁應用程式 (ASP.NET MVC)
Google API 支援網路伺服器應用程式適用的 OAuth 2.0。為成功執行下列程式碼,您必須先在 Google API 控制台中為專案新增重新導向 URI。由於您要使用 FlowMetadata
及其預設設定,因此請將重新導向 URI 設為 your_site/AuthCallback/IndexAsync
。
如要尋找 OAuth 2.0 憑證的重新導向 URI,請按照下列指示操作:
- 在 API 控制台中開啟「憑證」頁面。
- 如果您尚未建立 OAuth 2.0 憑證,請按一下 [建立憑證 > OAuth 用戶端 ID]。
- 建立憑證後,請在「OAuth 2.0 用戶端 ID」部分按一下用戶端 ID (如果是網頁應用程式),即可查看或編輯重新導向網址。
在 IDE 中建立新的網頁應用程式專案後,請新增正確的 Google.Apis
NuGet 套件,以便使用雲端硬碟、YouTube 或您要使用的其他服務。然後加入 Google.Apis.Auth.MVC 套件。以下程式碼示範如何查詢 Google API 服務的 ASP.NET MVC 應用程式。
-
自行新增
FlowMetadata
的實作項目。using System; using System.Web.Mvc; using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.OAuth2.Flows; using Google.Apis.Auth.OAuth2.Mvc; using Google.Apis.Drive.v2; using Google.Apis.Util.Store; namespace Google.Apis.Sample.MVC4 { public class AppFlowMetadata : FlowMetadata { private static readonly IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = new ClientSecrets { ClientId = "PUT_CLIENT_ID_HERE", ClientSecret = "PUT_CLIENT_SECRET_HERE" }, Scopes = new[] { DriveService.Scope.Drive }, DataStore = new FileDataStore("Drive.Api.Auth.Store") }); public override string GetUserId(Controller controller) { // In this sample we use the session to store the user identifiers. // That's not the best practice, because you should have a logic to identify // a user. You might want to use "OpenID Connect". // You can read more about the protocol in the following link: // https://developers.google.com/accounts/docs/OAuth2Login. 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; } } } }
FlowMetadata
是抽象類別,其中包含您自己的邏輯,用於擷取使用者 ID 和您使用的IAuthorizationCodeFlow
。在上述程式碼範例中,系統會使用正確的範圍、用戶端密鑰和資料儲存庫來建立新的
GoogleAuthorizationCodeFlow
。建議您自行新增IDataStore
的實作,例如,您可以使用EntityFramework
來編寫實作項目。 -
實作使用 Google API 服務的您自己的控制器。下列範例使用
DriveService
:using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web.Mvc; using Google.Apis.Auth.OAuth2.Mvc; using Google.Apis.Drive.v2; using Google.Apis.Services; using Google.Apis.Sample.MVC4; namespace Google.Apis.Sample.MVC4.Controllers { public class HomeController : Controller { public async Task<ActionResult> IndexAsync(CancellationToken cancellationToken) { var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()). AuthorizeAsync(cancellationToken); if (result.Credential != null) { var service = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = result.Credential, ApplicationName = "ASP.NET MVC Sample" }); // YOUR CODE SHOULD BE HERE.. // SAMPLE CODE: var list = await service.Files.List().ExecuteAsync(); ViewBag.Message = "FILE COUNT IS: " + list.Items.Count(); return View(); } else { return new RedirectResult(result.RedirectUri); } } } }
-
實作自己的回呼控制器。實作結果應如下所示:
using Google.Apis.Sample.MVC4; namespace Google.Apis.Sample.MVC4.Controllers { public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController { protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData { get { return new AppFlowMetadata(); } } } }
服務帳戶
Google API 也支援服務帳戶。有別於用戶端應用程式要求存取使用者資料的情況,服務帳戶會提供用戶端應用程式本身的資料存取權。
您的用戶端應用程式使用從 Google API 控制台下載的私密金鑰,簽署存取權杖的要求。建立新的用戶端 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
。