เอกสารนี้อธิบาย OAuth 2.0 กรณีที่ควรใช้ วิธีรับรหัสไคลเอ็นต์ และวิธีใช้กับไลบรารีของไคลเอ็นต์ Google API สำหรับ .NET
โปรโตคอล OAuth 2.0
OAuth 2.0 คือโปรโตคอลการให้สิทธิ์ที่ Google APIs ใช้ คุณควรทำความคุ้นเคยกับโปรโตคอลดังกล่าวด้วยการอ่านลิงก์ต่อไปนี้
การรับรหัสไคลเอ็นต์และข้อมูลลับ
คุณสามารถดูรหัสไคลเอ็นต์และข้อมูลลับได้ในคอนโซล Google API รหัสไคลเอ็นต์มีอยู่หลายประเภท ดังนั้นโปรดตรวจสอบว่าใช้ประเภทที่ถูกต้องสำหรับแอปพลิเคชันของคุณ
- รหัสไคลเอ็นต์ของเว็บแอปพลิเคชัน
- รหัสไคลเอ็นต์แอปพลิเคชันที่ติดตั้ง
- รหัสไคลเอ็นต์ของบัญชีบริการ
ในข้อมูลโค้ดแต่ละรายการด้านล่าง (ยกเว้นบัญชีบริการ 1 บัญชี) คุณต้องดาวน์โหลดรหัสลับไคลเอ็นต์และจัดเก็บไว้เป็น client_secrets.json
ในโปรเจ็กต์
ข้อมูลเข้าสู่ระบบ
ข้อมูลเข้าสู่ระบบของผู้ใช้
UserCredential
เป็นคลาสตัวช่วยที่ปลอดภัยสำหรับชุดข้อความซึ่งใช้โทเค็นเพื่อการเข้าถึงเพื่อเข้าถึงทรัพยากรที่มีการป้องกัน
โดยปกติแล้วโทเค็นเพื่อการเข้าถึงจะหมดอายุหลังผ่านไป 1 ชั่วโมง โดยระบบจะแสดงข้อผิดพลาดหากพยายามใช้งาน
UserCredential
และ AuthorizationCodeFlow
จะ "รีเฟรช" โทเค็นโดยอัตโนมัติ ซึ่งหมายถึงการรับโทเค็นเพื่อการเข้าถึงใหม่เลย
ซึ่งทำโดยใช้โทเค็นการรีเฟรชที่ใช้ได้นาน ซึ่งคุณจะได้รับพร้อมโทเค็นเพื่อการเข้าถึงหากคุณใช้พารามิเตอร์ access_type=offline
ระหว่างขั้นตอนรหัสการให้สิทธิ์
ในแอปพลิเคชันส่วนใหญ่ ขอแนะนำให้จัดเก็บโทเค็นเพื่อการเข้าถึงของข้อมูลเข้าสู่ระบบและโทเค็นการรีเฟรชไว้ในพื้นที่เก็บข้อมูลถาวร มิเช่นนั้น คุณจะต้องแสดงหน้าการให้สิทธิ์ในเบราว์เซอร์ให้กับผู้ใช้ปลายทางทุกชั่วโมง เนื่องจากโทเค็นเพื่อการเข้าถึงจะหมดอายุภายใน 1 ชั่วโมงหลังจากที่คุณได้รับ
หากต้องการตรวจสอบว่าโทเค็นเพื่อการเข้าถึงและโทเค็นการรีเฟรชยังคงอยู่ คุณอาจระบุการใช้งาน IDataStore
ด้วยตนเองหรือจะใช้การติดตั้งใช้งานอย่างใดอย่างหนึ่งต่อไปนี้ที่ไลบรารีมีให้ก็ได้
-
FileDataStore
สำหรับ .NET จะทำให้ข้อมูลเข้าสู่ระบบคงอยู่ถาวรในไฟล์
ข้อมูลเข้าสู่ระบบของบริการ
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(); ... } } }
-
ในโค้ดตัวอย่างนี้ อินสแตนซ์
UserCredential
ใหม่จะสร้างขึ้นโดยเรียกใช้เมธอดGoogleWebAuthorizationBroker.AuthorizeAsync
เมธอดแบบคงที่นี้จะได้รับสิ่งต่อไปนี้- รหัสลับไคลเอ็นต์ (หรือสตรีมไปยังรหัสลับไคลเอ็นต์)
- ขอบเขตที่จำเป็น
- ตัวระบุผู้ใช้
- โทเค็นการยกเลิกสำหรับยกเลิกการดำเนินการ
- พื้นที่เก็บข้อมูลที่ไม่บังคับ หากไม่ได้ระบุพื้นที่เก็บข้อมูล ค่าเริ่มต้นจะเป็น
FileDataStore
พร้อมโฟลเดอร์Google.Apis.Auth
ตามค่าเริ่มต้น โฟลเดอร์นี้จะสร้างขึ้นในEnvironment.SpecialFolder.ApplicationData
-
UserCredential
ที่ส่งคืนโดยเมธอดนี้ได้รับการตั้งค่าเป็นHttpClientInitializer
ในBooksService
(โดยใช้ตัวเริ่มต้น) ตามที่อธิบายไว้ข้างต้น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 สำหรับแอปพลิเคชันเว็บเซิร์ฟเวอร์
Google.Apis.Auth.AspNetCore3 เป็นไลบรารีที่แนะนำสำหรับใช้กับสถานการณ์ OAuth 2.0 ที่ใช้ Google ส่วนใหญ่ในแอปพลิเคชัน ASP.NET Core 3 ใช้งานเครื่องจัดการการตรวจสอบสิทธิ์ OpenIdConnect
ของ Google โดยเฉพาะ โดยจะรองรับการตรวจสอบสิทธิ์ที่เพิ่มขึ้น และกำหนด IGoogleAuthProvider
ที่แทรกได้เพื่อระบุข้อมูลเข้าสู่ระบบ Google ที่ใช้กับ Google APIs ได้
ส่วนนี้จะอธิบายวิธีกำหนดค่าและใช้ Google.Apis.Auth.AspNetCore3 โค้ดที่แสดงที่นี่อิงจาก Google.Apis.Auth.AspNetCore3.IntegrationTests ซึ่งเป็นแอปพลิเคชัน ASP.NET Core 3 แบบมาตรฐานที่ทำงานได้อย่างเต็มรูปแบบ
หากคุณต้องการทำตามเอกสารประกอบฉบับนี้เป็นบทแนะนำ คุณจะต้องใช้แอปพลิเคชัน ASP.NET Core 3 ของคุณเอง และต้องทำตามขั้นตอนเหล่านี้ให้เสร็จก่อน
ข้อกำหนดเบื้องต้น
- ติดตั้งแพ็กเกจ Google.Apis.Auth.AspNetCore3
- เราใช้ Google ไดรฟ์ API คุณจึงต้องติดตั้งแพ็กเกจ Google.Apis.Drive.v3 ด้วย
- สร้างโปรเจ็กต์ Google Cloud หากยังไม่มี ทำตาม วิธีการเหล่านี้เพื่อดำเนินการ ซึ่งจะเป็นโปรเจ็กต์ที่คุณตรวจพบแอป
- ตรวจสอบว่าได้เปิดใช้ API ของ Google ไดรฟ์แล้ว หากต้องการเปิดใช้ API ให้ทำตาม วิธีการเหล่านี้
-
สร้างข้อมูลเข้าสู่ระบบการให้สิทธิ์ที่จะระบุตัวตนแอปของคุณให้ Google ทราบ ทำตาม
วิธีการเหล่านี้เพื่อสร้างข้อมูลเข้าสู่ระบบการให้สิทธิ์และดาวน์โหลดไฟล์
client_secrets.json
ไฮไลต์ 2 ประการ ได้แก่- โปรดทราบว่าประเภทของข้อมูลเข้าสู่ระบบต้องเป็นเว็บแอปพลิเคชัน
- สำหรับการเรียกใช้แอปนี้ URI การเปลี่ยนเส้นทางเพียงรายการเดียวที่คุณต้องเพิ่มคือ
https://localhost:5001/signin-oidc
กำหนดค่าแอปพลิเคชันให้ใช้ Google.Apis.Auth.AspNetCore3
มีการกำหนดค่า Google.Apis.Auth.AspNetCore3 ในคลาส Startup
หรือทางเลือกอื่นที่คล้ายกันที่คุณอาจใช้อยู่ ข้อมูลโค้ดต่อไปนี้ดึงมาจาก
Startup.cs
ในโปรเจ็กต์ Google.Apis.Auth.AspNetCore3.IntegrationTests
-
เพิ่มคำสั่งต่อไปนี้ลงในไฟล์
Startup.cs
using Google.Apis.Auth.AspNetCore3;
-
ในเมธอด
Startup.ConfigureServices
ให้เพิ่มโค้ดต่อไปนี้ ให้เปลี่ยนตัวยึดตำแหน่งรหัสไคลเอ็นต์และรหัสลับไคลเอ็นต์ด้วยค่าที่มีอยู่ในไฟล์client_secrets.json
คุณโหลดค่าเหล่านี้ได้โดยตรงจากไฟล์ JSON หรือจะเก็บไว้ด้วยวิธีที่ปลอดภัยอื่นๆ ก็ได้ ลองดูเมธอดClientInfo.Load
ในโปรเจ็กต์ Google.Apis.Auth.AspNetCore3.IntegrationTests สำหรับตัวอย่างวิธีโหลดค่าเหล่านี้จากไฟล์ 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 APIs ในนามของผู้ใช้
ตอนนี้คุณพร้อมที่จะเพิ่มเมธอดการดำเนินการไปยังตัวควบคุมที่กำหนดให้ต้องมีข้อมูลเข้าสู่ระบบของผู้ใช้เพื่อเข้าถึง Google APIs ในนามของผู้ใช้แล้ว ข้อมูลโค้ดต่อไปนี้แสดงวิธีแสดงรายการไฟล์ในบัญชี Google ไดรฟ์ของผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว ลองสังเกต 2 สิ่งต่อไปนี้เป็นส่วนใหญ่
-
ผู้ใช้ไม่เพียงต้องผ่านการตรวจสอบสิทธิ์ แต่ยังต้องมอบขอบเขต
https://www.googleapis.com/auth/drive.readonly
ให้กับแอปพลิเคชันของคุณซึ่งคุณระบุผ่านแอตทริบิวต์GoogleScopedAuthorize
ด้วย -
เราใช้กลไกการแทรกทรัพยากร Dependency มาตรฐานของ 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); }
ต่อไปนี้เป็นข้อมูลเบื้องต้น คุณสามารถดู
HomeController.cs
จากโปรเจ็กต์ Google.Apis.Auth.AspNetCore3.IntegrationTests
เพื่อดูว่าจะบรรลุเป้าหมายต่อไปนี้ได้อย่างไร
- การตรวจสอบสิทธิ์ผู้ใช้เท่านั้น โดยไม่มีขอบเขตที่เจาะจง
- ฟังก์ชันการออกจากระบบ
- การให้สิทธิ์ที่เพิ่มขึ้นผ่านรหัส โปรดทราบว่าข้อมูลโค้ดด้านบนแสดงการให้สิทธิ์ที่เพิ่มขึ้นผ่านแอตทริบิวต์
- ตรวจสอบขอบเขตที่ให้สิทธิ์ในปัจจุบัน
- ตรวจสอบโทเค็นเพื่อการเข้าถึงและรีเฟรชโทเค็น
- บังคับรีเฟรชโทเค็นเพื่อการเข้าถึง โปรดทราบว่าคุณไม่ต้องดำเนินการนี้ด้วยตนเองเนื่องจาก Google.Apis.Auth.AspNetCore3 จะตรวจพบว่าโทเค็นเพื่อการเข้าถึงหมดอายุหรือใกล้จะหมดอายุแล้วหรือไม่ และจะรีเฟรชโทเค็นดังกล่าวโดยอัตโนมัติ
บัญชีบริการ
Google API ยังรองรับบัญชีบริการด้วย บัญชีบริการจะให้สิทธิ์เข้าถึงข้อมูลของแอปพลิเคชันไคลเอ็นต์ ซึ่งต่างจากสถานการณ์ที่แอปพลิเคชันไคลเอ็นต์จะขอสิทธิ์เข้าถึงข้อมูลของผู้ใช้ปลายทาง
แอปพลิเคชันไคลเอ็นต์จะลงนามในคำขอโทเค็นเพื่อการเข้าถึงโดยใช้คีย์ส่วนตัวที่ดาวน์โหลดมาจากคอนโซล Google API หลังจากสร้างรหัสไคลเอ็นต์ใหม่แล้ว คุณควรเลือกประเภทแอปพลิเคชัน "บัญชีบริการ" จากนั้นจึงดาวน์โหลดคีย์ส่วนตัวได้ ดู ตัวอย่างบัญชีบริการที่ใช้ 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
เช่นเดียวกับในโค้ดตัวอย่างอื่นๆ ทั้งหมด