OAuth 2.0

เอกสารนี้อธิบาย 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 เช่นเดียวกับในโค้ดตัวอย่างอื่นๆ ทั้งหมด