Tài liệu này mô tả OAuth 2.0, thời điểm sử dụng, cách lấy mã ứng dụng và cách dùng mã này trong Thư viện ứng dụng .NET cho API của Google.
Giao thức OAuth 2.0
OAuth 2.0 là giao thức cấp phép được API Google sử dụng. Bạn có thể làm quen với giao thức này bằng cách đọc các đường liên kết sau:
Thu thập mã ứng dụng khách và khóa bí mật
Bạn có thể lấy mã ứng dụng và mã thông báo bí mật trên Bảng điều khiển API của Google. Có nhiều loại mã ứng dụng khách, nên hãy nhớ chọn loại mã chính xác cho ứng dụng của bạn:
- Mã ứng dụng khách ứng dụng web
- ID ứng dụng khách đã cài đặt
- Mã khách hàng của tài khoản dịch vụ
Trong mỗi đoạn mã bên dưới (ngoại trừ đoạn mã Tài khoản dịch vụ), bạn phải tải mã bí mật của ứng dụng xuống và lưu trữ mã đó dưới dạng client_secrets.json
trong dự án.
Thông tin xác thực
Thông tin xác thực người dùng
UserCredential
là một lớp trợ giúp an toàn cho luồng sử dụng mã thông báo truy cập để truy cập vào các tài nguyên được bảo vệ.
Mã thông báo truy cập thường hết hạn sau 1 giờ. Sau đó, bạn sẽ gặp lỗi nếu cố gắng sử dụng mã đó.
UserCredential
và
AuthorizationCodeFlow
tự động xử lý "Refreshing" mã thông báo, chỉ đơn giản có nghĩa là nhận
mã truy cập mới.
Bạn có thể thực hiện việc này bằng cách sử dụng một mã làm mới lâu dài mà bạn sẽ nhận được cùng với
mã truy cập nếu sử dụng thông số
access_type=offline
trong quy trình mã uỷ quyền.
Trong hầu hết ứng dụng, bạn nên lưu trữ mã truy cập và mã làm mới của thông tin đăng nhập trong bộ nhớ ổn định. Nếu không, bạn cần hiển thị cho người dùng cuối một trang uỷ quyền trong trình duyệt mỗi giờ vì mã truy cập sẽ hết hạn sau một giờ kể từ khi bạn nhận được mã.
Để đảm bảo mã truy cập và các mã làm mới vẫn tồn tại, bạn có thể tự triển khai IDataStore
hoặc sử dụng một trong những cách triển khai sau do thư viện cung cấp:
-
FileDataStore
đối với .NET giúp đảm bảo rằng thông tin xác thực sẽ tồn tại trong một tệp.
Thông tin xác thực tài khoản dịch vụ
ServiceAccountCredential
tương tự như UserCredential
, nhưng phục vụ mục đích khác.
Google OAuth 2.0 hỗ trợ các tương tác từ máy chủ đến máy chủ, chẳng hạn như các tương tác giữa một ứng dụng web và Google Cloud Storage.
Ứng dụng yêu cầu phải chứng minh danh tính riêng để có quyền truy cập vào API và người dùng cuối không cần phải tham gia.
ServiceAccountCredential
lưu trữ một khoá riêng tư, dùng để ký một yêu cầu nhận mã truy cập mới.
Cả UserCredential
và ServiceAccountCredential
đều triển khai IConfigurableHttpClientInitializer
để bạn có thể đăng ký từng yếu tố này dưới dạng:
- Trình xử lý phản hồi không thành công, vì vậy, trình xử lý sẽ làm mới mã thông báo nếu nhận được mã trạng thái HTTP
401
. - Trình chặn, để chặn tiêu đề
Authorization
trên mọi yêu cầu.
Các ứng dụng đã cài đặt
Mã mẫu sử dụng API Sách:
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(); ... } } }
-
Trong mã mẫu này, một phiên bản
UserCredential
mới được tạo bằng cách gọi phương thứcGoogleWebAuthorizationBroker.AuthorizeAsync
. Phương thức tĩnh này có các thông tin sau:- Mật khẩu ứng dụng khách (hoặc một luồng tới mật khẩu ứng dụng khách).
- Các phạm vi bắt buộc.
- Giá trị nhận dạng người dùng.
- Mã thông báo huỷ để huỷ một hoạt động.
- Lưu trữ dữ liệu không bắt buộc. Nếu kho dữ liệu không được chỉ định, giá trị mặc định sẽ là
FileDataStore
với thư mụcGoogle.Apis.Auth
mặc định. Thư mục được tạo trongEnvironment.SpecialFolder.ApplicationData
.
-
UserCredential
được trả về bằng phương thức này sẽ được đặt thànhHttpClientInitializer
trênBooksService
(bằng cách sử dụng trình khởi tạo). Như đã giải thích ở trên,UserCredential
sẽ triển khai một trình khởi chạy ứng dụng HTTP. -
Lưu ý rằng trong mã mẫu ở trên, thông tin mật của ứng dụng khách được tải từ một tệp, nhưng bạn cũng có thể làm như sau:
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"));
Hãy xem Mẫu sách của chúng tôi.
Ứng dụng web (ASP.NET Core 3)
API của Google hỗ trợ OAuth 2.0 cho Ứng dụng máy chủ web.
Google.Apis.Auth.AspNetCore3 là thư viện mà bạn nên sử dụng cho hầu hết các trường hợp OAuth 2.0 dựa trên Google trong các ứng dụng ASP.NET Core 3. Triển khai một trình xử lý xác thực OpenIdConnect
dành riêng cho Google. API này hỗ trợ tính năng ủy quyền từng phần và xác định một IGoogleAuthProvider
có thể chèn để cung cấp thông tin đăng nhập của Google có thể dùng với các API của Google.
Phần này mô tả cách định cấu hình và sử dụng Google.Apis.Auth.AspNetCore3. Mã được hiển thị ở đây dựa trên Google.Apis.Auth.AspNetCore3.IntegrationTests là một ứng dụng ASP.NET Core 3 chuẩn, hoạt động đầy đủ.
Nếu muốn làm theo tài liệu này làm hướng dẫn, bạn sẽ cần ứng dụng ASP.NET Core 3 của riêng mình và hoàn thành các bước này như một điều kiện tiên quyết.
Điều kiện tiên quyết
- Cài đặt gói Google.Apis.Auth.AspNetCore3.
- Chúng tôi đang dùng API Google Drive nên bạn cũng cần cài đặt gói Google.Apis.Drive.v3.
- Tạo một dự án Google Cloud nếu bạn chưa có. Hãy làm theo những hướng dẫn này để làm điều đó. Đây sẽ là dự án mà ứng dụng của bạn được xác định.
- Hãy nhớ bật API Google Drive. Để bật API, hãy làm theo những hướng dẫn này.
-
Tạo thông tin đăng nhập ủy quyền sẽ giúp Google xác định ứng dụng của bạn. Làm theo
những hướng dẫn này để tạo thông tin đăng nhập ủy quyền và tải tệp
client_secrets.json
xuống. Hai điểm nổi bật:- Lưu ý rằng thông tin đăng nhập phải là Ứng dụng web.
- Để chạy ứng dụng này, bạn chỉ cần thêm URI chuyển hướng là
https://localhost:5001/signin-oidc
.
Định cấu hình ứng dụng của bạn để sử dụng Google.Apis.Auth.AspNetCore3
Google.Apis.Auth.AspNetCore3 được định cấu hình trong lớp Startup
hoặc thay thế tương tự mà bạn có thể đang sử dụng. Các đoạn mã sau được trích xuất từ
Startup.cs
trong dự án Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Thêm nội dung sau bằng lệnh sử dụng vào tệp
Startup.cs
.using Google.Apis.Auth.AspNetCore3;
-
Trong phương thức
Startup.ConfigureServices
, hãy thêm mã sau, thay đổi mã ứng dụng khách và phần giữ chỗ bí mật của ứng dụng bằng các giá trị có trong tệpclient_secrets.json
. Bạn có thể tải trực tiếp các giá trị này từ tệp JSON hoặc lưu trữ chúng theo bất kỳ cách nào khác an toàn. Hãy tham khảo phương thứcClientInfo.Load
trong dự án Google.Apis.Auth.AspNetCore3.integrationTests để xem ví dụ về cách tải trực tiếp các giá trị này từ tệp 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}; }); }
-
Trong phương thức
Startup.Configure
, hãy nhớ thêm các thành phần phần mềm trung gian uỷ quyền và ASP.NET Core 3 vào quy trình, cũng như các lệnh chuyển hướng HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Sử dụng thông tin đăng nhập của người dùng để truy cập vào các API của Google thay mặt cho họ
Bây giờ, bạn đã sẵn sàng để thêm các phương thức hành động vào bộ điều khiển yêu cầu thông tin đăng nhập của người dùng thay mặt cho họ truy cập vào các API của Google. Đoạn mã sau đây cho biết cách liệt kê các tệp trên tài khoản Google Drive của người dùng đã xác thực. Hãy lưu ý chủ yếu hai điều sau:
-
Người dùng không chỉ cần được xác thực, mà còn cần cấp phạm vi
https://www.googleapis.com/auth/drive.readonly
cho ứng dụng, mà bạn chỉ định thông qua thuộc tínhGoogleScopedAuthorize
. -
Chúng tôi đang sử dụng cơ chế chèn phần phụ thuộc tiêu chuẩn của ASP.NET Core 3\39 để nhận một
IGoogleAuthProvider
mà chúng tôi sử dụng để lấy thông tin xác thực của người dùng.
Mã:
-
Trước tiên, hãy thêm các nội dung sau bằng lệnh vào bộ điều khiển.
using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;
-
Thêm thao tác điều khiển như sau (và đi kèm với thao tác đơn giản đó để nhận mô hình
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); }
Và đây là những điều cơ bản. Bạn có thể xem HomeController.cs
từ dự án Google.Apis.Auth.AspNetCore3.TíchTestTests để tìm hiểu cách bạn có thể đạt được:
- Chỉ xác thực người dùng, không có phạm vi cụ thể
- Chức năng đăng xuất
- Ủy quyền gia tăng qua mã. Xin lưu ý rằng đoạn mã trên sẽ cho thấy mã ủy quyền gia tăng thông qua các thuộc tính.
- Kiểm tra các phạm vi được cấp hiện tại
- Kiểm tra mã truy cập và các mã thông báo làm mới
- Buộc làm mới mã thông báo truy cập. Xin lưu ý rằng bạn không phải tự làm điều này vì Google.Apis.Auth.AspNetCore3 sẽ phát hiện xem mã truy cập đã hết hạn hay sắp hết hạn và sẽ tự động làm mới mã.
Ứng dụng web (ASP.NET MVC)
API của Google hỗ trợ
OAuth 2.0 cho Ứng dụng máy chủ web.
Để chạy được mã sau, trước tiên bạn phải thêm một URI chuyển hướng vào dự án của mình trong Google API Console.
Vì bạn sẽ sử dụng FlowMetadata
và các tuỳ chọn cài đặt mặc định của tuỳ chọn này,
hãy đặt URI chuyển hướng thành
your_site/AuthCallback/IndexAsync
.
Để tìm các URI chuyển hướng cho thông tin xác thực OAuth 2.0 của bạn, hãy làm như sau:
- Mở trang Thông tin xác thực trong Bảng điều khiển API.
- Hãy tạo thông tin xác thực OAuth 2.0 bằng cách nhấp vào Tạo thông tin xác thực > Mã ứng dụng khách OAuth (nếu bạn chưa thực hiện).
- Sau khi bạn tạo thông tin xác thực, hãy xem hoặc chỉnh sửa URL chuyển hướng bằng cách nhấp vào mã ứng dụng (đối với ứng dụng web) trong phần Mã ứng dụng OAuth 2.0.
Sau khi tạo một dự án ứng dụng web mới trong IDE, hãy thêm gói Google.Apis
NuGet phù hợp cho Drive, YouTube hoặc dịch vụ khác mà bạn muốn sử dụng. Sau đó, hãy thêm gói Google.Apis.Auth.MVC.
Mã sau đây minh hoạ ứng dụng ASP.NET MVC truy vấn dịch vụ API của Google.
-
Thêm cách triển khai
FlowMetadata
của riêng bạn.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
là một lớp trừu tượng chứa logic của riêng bạn để truy xuất giá trị nhận dạng người dùng vàIAuthorizationCodeFlow
mà bạn đang sử dụng.Trong mã mẫu trên, một
GoogleAuthorizationCodeFlow
mới được tạo với phạm vi phù hợp, mật khẩu ứng dụng khách và kho lưu trữ dữ liệu. Hãy cân nhắc việc thêm phương thức triển khaiIDataStore
của riêng bạn. Ví dụ: bạn có thể viết một phương thức sử dụngEntityFramework
. -
Triển khai bộ điều khiển có sử dụng dịch vụ API của Google.
Mẫu sau đây sử dụng
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); } } } }
-
Triển khai bộ điều khiển lệnh gọi lại của riêng bạn. Quá trình triển khai sẽ có dạng như sau:
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(); } } } }
Tài khoản dịch vụ
API Google cũng hỗ trợ Tài khoản dịch vụ. Không giống như trường hợp ứng dụng khách yêu cầu quyền truy cập vào dữ liệu của người dùng cuối, tài khoản dịch vụ cung cấp quyền truy cập vào dữ liệu của ứng dụng khách.
Ứng dụng khách ký yêu cầu một mã truy cập bằng một khoá riêng tư đã tải xuống từ Google API Console. Sau khi tạo mã ứng dụng khách mới, bạn nên chọn loại ứng dụng “Tài khoản dịch vụ” rồi có thể tải khoá riêng tư xuống. Hãy xem mẫu tài khoản dịch vụ bằng API Google Plus.
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(); } } }
Mã mẫu ở trên tạo ra một ServiceAccountCredential
.
Các phạm vi bắt buộc được đặt và có lệnh gọi đến FromCertificate
, việc này sẽ tải khóa riêng tư từ X509Certificate2
nhất định.
Như trong mọi mã mẫu khác, thông tin đăng nhập được đặt là HttpClientInitializer
.