W tym dokumencie opisujemy OAuth 2.0, podajemy, kiedy należy go używać, jak pozyskiwać identyfikatory klienta oraz jak korzystać z niego w bibliotece klienta interfejsu API Google dla .NET.
Protokół OAuth 2.0
OAuth 2.0 to protokół autoryzacji używany przez interfejsy API Google. Zapoznaj się z protokołem, czytając te artykuły:
Pobieranie identyfikatorów i tajnych kluczy klientów
Identyfikatory klienta i klucze tajne możesz pobrać w Konsoli interfejsów API Google. Istnieją różne typy identyfikatorów klienta, dlatego pamiętaj, aby wybrać odpowiedni typ dla swojej aplikacji:
- Identyfikatory klienta aplikacji internetowej
- Identyfikatory klienta zainstalowanej aplikacji
- Identyfikatory klienta konta usługi
W każdym z wyświetlanych fragmentów kodu (z wyjątkiem fragmentu kodu dotyczącego konta usługi) musisz pobrać klucz tajny klienta i zapisać go jako client_secrets.json
w projekcie.
Dane logowania
Dane logowania użytkownika
UserCredential
to klasa pomocnicza chroniąca wątki, która umożliwia korzystanie z tokena dostępu do zasobów chronionych.
Token dostępu wygasa zwykle po 1 godzinie. Po tym czasie, jeśli spróbujesz go użyć, pojawi się błąd.
UserCredential
AuthorizationCodeFlow
automatycznie „odświeża” token, co oznacza uzyskanie nowego tokena dostępu.
Aby to zrobić, użyj długoterminowego tokena odświeżania, który otrzymasz wraz z tokenem dostępu, jeśli podczas przepływu kodu autoryzacji użyjesz parametru access_type=offline
.
W większości aplikacji zaleca się przechowywanie tokena dostępu i tokena odświeżania w pamięci trwałej. W przeciwnym razie musisz co godzinę wyświetlać użytkownikowi stronę autoryzacji w przeglądarce, ponieważ token dostępu wygasa godzinę po jego otrzymaniu.
Aby zapewnić trwałość tokenów dostępu i odświeżania, możesz podać własną implementacjęIDataStore
lub użyć jednej z tych implementacji udostępnionych przez bibliotekę:
-
FileDataStore
w języku C# zapewnia, że dane uwierzytelniające będą trwałe w pliku.
ServiceAccountCredential
ServiceAccountCredential
jest podobna do UserCredential
, ale służy do innego celu.
Google OAuth 2.0 obsługuje interakcję między serwerami, na przykład między aplikacją internetową a Google Cloud Storage.
Aplikacja wykonująca żądanie musi potwierdzić swoją tożsamość, aby uzyskać dostęp do interfejsu API. Nie wymaga to udziału użytkownika końcowego.
ServiceAccountCredential
przechowuje klucz prywatny, który służy do podpisywania żądań w celu uzyskania nowego tokena dostępu.
Zarówno UserCredential
, jak i ServiceAccountCredential
implementują IConfigurableHttpClientInitializer
, więc możesz zarejestrować je jako:
- Obsługa odpowiedzi z błędem, która odświeża token, jeśli otrzyma kod stanu HTTP
401
. - Przechwytywanie, aby przechwytywać nagłówek
Authorization
w przypadku każdego żądania.
Zainstalowane aplikacje
Przykładowy kod korzystający z interfejsu 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(); ... } } }
-
W tym przykładowym kodzie nowa instancja
UserCredential
jest tworzona przez wywołanie metodyGoogleWebAuthorizationBroker.AuthorizeAsync
. Ta metoda statyczna zwraca:- tajny klucz klienta (lub strumień do tajnego klucza klienta);
- Wymagane zakresy.
- Identyfikator użytkownika.
- Token anulowania operacji.
- opcjonalny obiekt pamięci danych. Jeśli nie określisz bazy danych, domyślnie zostanie użyta baza danych
FileDataStore
z domyślnym folderemGoogle.Apis.Auth
. Folder zostanie utworzony wEnvironment.SpecialFolder.ApplicationData
.
-
UserCredential
zwracany przez tę metodę jest ustawiany jakoHttpClientInitializer
w obiekcieBooksService
(za pomocą funkcji inicjującej). Jak już wspomnieliśmy,UserCredential
implementuje inicjalizator klienta HTTP. -
Zwróć uwagę, że w przykładowym kodzie informacje tajne klienta są wczytywane z pliku, ale możesz też wykonać te czynności:
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"));
Zapoznaj się z przykładem książki.
Aplikacje internetowe (ASP.NET Core 3)
Interfejsy API Google obsługują OAuth 2.0 w internetowych aplikacjach serwerowych.
Biblioteka
Google.Apis.Auth.AspNetCore3 jest zalecana do większości scenariuszy OAuth 2.0 Google w aplikacjach ASP.NET Core 3. Wdraża interfejs obsługi autoryzacji OpenIdConnect
specyficzny dla Google. Obsługuje stopniowe uwierzytelnianie i określa funkcję do wstrzykiwania
IGoogleAuthProvider
, która służy do podawania danych logowania Google, których można używać z interfejsami API Google.
W tej sekcji opisaliśmy, jak skonfigurować i używać pakietu Google.Apis.Auth.AspNetCore3. Pokazujemy tu kod oparty na komponencie Google.Apis.Auth.AspNetCore3.IntegrationTests, który jest w pełni działającą standardową aplikacją ASP.NET Core 3.
Jeśli chcesz postępować zgodnie z tą dokumentacją jako samouczkiem, musisz mieć własną aplikację ASP.NET Core 3 i wykonać te czynności w ramach wstępnej konfiguracji.
Wymagania wstępne
- Zainstaluj pakiet Google.Apis.Auth.AspNetCore3.
- Używamy interfejsu API Dysku Google, więc musisz też zainstalować pakiet Google.Apis.Drive.v3.
- Utwórz projekt Google Cloud (jeśli jeszcze go nie masz). Aby to zrobić, postępuj zgodnie z tymi instrukcjami. Będzie to projekt, z którym będzie powiązana Twoja aplikacja.
- Pamiętaj, aby włączyć interfejs Drive API. Aby włączyć interfejsy API, wykonaj te instrukcje.
-
Utwórz dane uwierzytelniające, które będą identyfikować Twoją aplikację w Google. Aby utworzyć dane uwierzytelniające i pobrać plik
client_secrets.json
, wykonaj te instrukcje. 2 najważniejsze informacje:- Pamiętaj, że typ danych logowania musi być ustawiony na Aplikacja internetowa.
- Aby uruchomić tę aplikację, musisz dodać tylko identyfikator URI przekierowania:
https://localhost:5001/signin-oidc
.
Skonfiguruj aplikację tak, aby używała Google.Apis.Auth.AspNetCore3
Google.Apis.Auth.AspNetCore3 jest skonfigurowana w klasie Startup
lub podobnej alternatywie, z której możesz korzystać. Poniższe fragmenty kodu pochodzą z projektu
Startup.cs
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Dodaj do pliku
Startup.cs
tę dyrektywę.using Google.Apis.Auth.AspNetCore3;
-
W metodzie
Startup.ConfigureServices
dodaj ten kod, zastępując wskaźniki zastępcze identyfikatora klienta i tajnego klucza klienta wartościami zawartymi w plikuclient_secrets.json
. Możesz załadować te wartości bezpośrednio z pliku JSON lub zapisać je w dowolny inny bezpieczny sposób. Aby dowiedzieć się, jak wczytywać te wartości bezpośrednio z pliku JSON, zapoznaj się z metodąClientInfo.Load
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTestspublic 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}; }); }
-
W metodzie
Startup.Configure
pamiętaj, aby dodać do potoku komponenty pośredniczące ASP.NET Core 3 do uwierzytelniania i autoryzacji, a także przekierowania HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Używanie danych logowania użytkownika do uzyskiwania dostępu do interfejsów Google API w jego imieniu
Możesz teraz dodać do kontrolerów metody działania, które wymagają danych logowania użytkownika, aby uzyskać dostęp do interfejsów API Google w jego imieniu. Ten fragment kodu pokazuje, jak wyświetlić listę plików na koncie Dysku Google uwierzytelnionego użytkownika. Zwróć uwagę przede wszystkim na 2 rzeczy:
-
Użytkownik musi nie tylko przejść uwierzytelnianie, ale też przyznać Twojej aplikacji zakres
https://www.googleapis.com/auth/drive.readonly
, który określasz za pomocą atrybutuGoogleScopedAuthorize
. -
Korzystamy ze standardowego mechanizmu wstrzykiwania zależności w ASP.NET Core 3, aby otrzymywać obiekt
IGoogleAuthProvider
, którego używamy do uzyskiwania danych uwierzytelniających użytkownika.
Kod:
-
Najpierw dodaj do kontrolera te dyrektywy.
using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;
-
Dodaj działanie kontrolera w ten sposób (i dołącz do niego widok, który przyjmuje model
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); }
To są podstawy. Aby dowiedzieć się, jak to zrobić, możesz zapoznać się z projektem
HomeController.cs
z pakietu Google.Apis.Auth.AspNetCore3.IntegrationTests, w którym znajdziesz:
- tylko uwierzytelnianie użytkownika bez określonych zakresów uprawnień;
- Wylogowanie użytkownika
- Autoryzacja przyrostowa z kodem. Zwróć uwagę, że przykład pokazuje stopniowe autoryzowanie z atrybutami.
- Sprawdzanie przyznanych zakresów
- Sprawdzanie tokenów dostępu i odświeżania
- Wymuś odświeżenie tokena dostępu. Nie musisz tego robić samodzielnie, ponieważ Google.Apis.Auth.AspNetCore3 wykryje, czy token dostępu wygasł lub wygaśnie wkrótce i automatycznie go odświeży.
Konto usługi
Interfejsy API Google obsługują też konta usługi. W przeciwieństwie do sytuacji, w której aplikacja kliencka prosi o dostęp do danych użytkownika, konta usługi zapewniają dostęp do danych aplikacji klienckiej.
Aplikacja klienta podpisuje żądanie tokena dostępu za pomocą klucza prywatnego pobranego z konsoli interfejsów API Google. Po utworzeniu nowego identyfikatora klienta wybierz typ aplikacji Konto usługi, a potem pobierz klucz prywatny. Zapoznaj się z naszym przykładem konta usługi korzystającego z interfejsu 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(); } } }
Ten przykład tworzy ServiceAccountCredential
.
Wymagane zakresy są ustawione, a wywołanie funkcji FromCertificate
wczytuje klucz prywatny z danego FromCertificate
.X509Certificate2
Podobnie jak we wszystkich innych przykładowych fragmentach kodu, dane logowania są ustawione jako HttpClientInitializer
.