W tym dokumencie opisujemy protokół OAuth 2.0 oraz opisujemy, kiedy i jak uzyskiwać identyfikatory klientów z użyciem protokołu OAuth 2.0, oraz jak go używać z biblioteką klienta interfejsów API Google dla języka .NET.
Protokół OAuth 2.0
OAuth 2.0 to protokół autoryzacji używany przez interfejsy API Google. Aby zapoznać się z protokołem, przeczytaj te linki:
Uzyskiwanie identyfikatorów klientów i obiektów tajnych
Identyfikatory klientów i obiekty tajne możesz uzyskać w Konsoli interfejsów API Google. Istnieją różne typy identyfikatorów klienta, więc sprawdź, czy pobierasz odpowiedni typ dla swojej aplikacji:
- Identyfikatory klienta aplikacji internetowej
- Identyfikatory klienta zainstalowanej aplikacji.
- Identyfikatory klientów konta usługi
W każdym z poniższych fragmentów kodu (z wyjątkiem konta usługi) musisz pobrać tajny klucz klienta i zapisać go w projekcie jako client_secrets.json
.
Dane uwierzytelniające
Dane logowania użytkownika
UserCredential
to klasa pomocnicza zapewniająca bezpieczeństwo wątku służąca do uzyskiwania dostępu do zabezpieczonych zasobów przy użyciu tokena dostępu.
Token dostępu zwykle wygasa po 1 godzinie, a po jego użyciu pojawia się komunikat o błędzie, jeśli spróbujesz go użyć.
UserCredential
i AuthorizationCodeFlow
dbają o automatyczne „odświeżanie” tokena, co oznacza samo uzyskanie nowego tokena dostępu.
W tym celu wykorzystuje się token odświeżania o długotrwałym czasie, który otrzymujesz razem z tokenem dostępu, jeśli podczas przepływu kodu autoryzacji używasz parametru access_type=offline
.
W większości aplikacji zalecane jest przechowywanie tokena dostępu i tokena odświeżania w pamięci trwałej. W przeciwnym razie trzeba co godzinę wyświetlać użytkownikowi stronę autoryzacji w przeglądarce, ponieważ token dostępu wygasa po upływie godziny od jego otrzymania.
Aby mieć pewność, że tokeny dostępu i odświeżania będą działać, możesz udostępnić własną implementację IDataStore
lub użyć jednej z tych implementacji zapewnianych przez bibliotekę:
-
FileDataStore
dla .NET zapewnia, że dane logowania są trwałe w pliku.
ServiceAccountCredential
ServiceAccountCredential
jest podobny do właściwości UserCredential
, ale ma inny cel.
Google OAuth 2.0 obsługuje interakcje między serwerami, takie jak między aplikacją internetową a Google Cloud Storage.
Aplikacja żądająca dostępu musi potwierdzić swoją tożsamość, aby uzyskać dostęp do interfejsu API. Użytkownik końcowy nie musi w tym uczestniczyć.
ServiceAccountCredential
przechowuje klucz prywatny, który służy do podpisywania żądania uzyskania nowego tokena dostępu.
Zarówno UserCredential
, jak i ServiceAccountCredential
implementują instancję IConfigurableHttpClientInitializer
, więc możesz zarejestrować każdą z nich jako:
- Moduł obsługi odpowiedzi zakończony niepowodzeniem, więc odświeży się token, jeśli otrzyma kod stanu HTTP
401
. - Przechwytywanie, aby przechwycić nagłówek
Authorization
przy każdym żądaniu.
Zainstalowane aplikacje
Przykładowy kod wygenerowany przy użyciu 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 uzyskuje te korzyści:- Tajny klucz klienta (lub strumień do tajnego klucza klienta).
- Wymagane zakresy.
- Identyfikator użytkownika.
- Token anulowania do anulowania operacji.
- Opcjonalny magazyn danych. Jeśli nie podasz magazynu danych, domyślną wartością będzie
FileDataStore
z domyślnym folderemGoogle.Apis.Auth
. Folder zostanie utworzony w aplikacjiEnvironment.SpecialFolder.ApplicationData
.
-
Wartość
UserCredential
zwracana przez tę metodę jest ustawiona jakoHttpClientInitializer
wBooksService
(przy użyciu inicjatora). Jak wyjaśniliśmy powyżej,UserCredential
implementuje inicjator klienta HTTP. -
Zwróć uwagę, że w powyższym przykładowym kodzie informacje o kluczu klienta są wczytywane z pliku, ale można też wykonywać 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 naszą próbką Książek.
Aplikacje internetowe (ASP.NET Core 3)
Interfejsy API Google obsługują protokół OAuth 2.0 dla aplikacji serwerowych.
Google.Apis.Auth.AspNetCore3 to zalecana biblioteka do użycia w większości przypadków opartych na protokole Google OAuth 2.0 w aplikacjach ASP.NET Core 3. Ma ona wbudowany moduł uwierzytelniania OpenIdConnect
specyficzny dla Google. Obsługuje uwierzytelnianie przyrostowe i określa wstrzykiwany IGoogleAuthProvider
do dostarczania danych logowania Google, których można używać z interfejsami API Google.
Ta sekcja zawiera informacje na temat konfigurowania i używania interfejsu Google.Apis.Auth.AspNetCore3. Pokazany tutaj kod jest oparty na Google.Apis.Auth.AspNetCore3.IntegrationTests – w pełni działającej, standardowej aplikacji ASP.NET Core 3.
Jeśli chcesz postępować zgodnie z tą dokumentacją jako samouczek, będziesz potrzebować własnej aplikacji ASP.NET Core 3. Konieczne jest też wykonanie tych czynności.
Wymagania wstępne
- Zainstaluj pakiet Google.Apis.Auth.AspNetCore3.
- Używamy interfejsu Google Drive API, więc musisz też zainstalować pakiet Google.Apis.Drive.v3.
- Utwórz projekt Google Cloud, jeśli jeszcze go nie masz. Aby to zrobić, wykonaj te instrukcje. To będzie projekt, z którym identyfikowana będzie Twoja aplikacja.
- Włącz interfejs Google Drive API. Aby włączyć interfejsy API, wykonaj te instrukcje.
-
Utwórz dane logowania, które pozwolą Google zidentyfikować Twoją aplikację. Wykonaj
te instrukcje, aby utworzyć dane uwierzytelniające i pobrać plik
client_secrets.json
. 2 najważniejsze informacje:- Zwróć uwagę, że dane logowania muszą być typu Aplikacja internetowa.
- Aby można było uruchomić tę aplikację, jedyny identyfikator URI przekierowania, który należy dodać, to
https://localhost:5001/signin-oidc
.
Skonfiguruj aplikację do korzystania z Google.Apis.Auth.AspNetCore3
Usługa Google.Apis.Auth.AspNetCore3 jest skonfigurowana w klasie Startup
lub podobnej opcji, której możesz używać. Poniższe fragmenty kodu zostały wyodrębnione z pliku
Startup.cs
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Dodaj do pliku
Startup.cs
tę dyrektywę using.using Google.Apis.Auth.AspNetCore3;
-
W metodzie
Startup.ConfigureServices
dodaj poniższy kod i zmień obiekty zastępcze identyfikatora klienta i tajnego klucza klienta wartościami, które znajdują się w plikuclient_secrets.json
. Możesz wczytać te wartości bezpośrednio z pliku JSON lub przechowywać je w dowolny inny bezpieczny sposób. Zapoznaj się z metodąClientInfo.Load
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests, aby zobaczyć, jak wczytać te wartości bezpośrednio z pliku 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}; }); }
-
W metodzie
Startup.Configure
dodaj do potoku komponenty uwierzytelniania i autoryzacji ASP.NET Core 3, a także przekierowania HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Używanie danych logowania użytkownika w celu uzyskiwania dostępu do interfejsów API Google w jego imieniu
Teraz możesz dodać do kontrolerów metody działań, które wymagają danych logowania użytkownika w celu uzyskania dostępu do interfejsów API Google w jego imieniu. Poniższy fragment pokazuje, jak wyświetlić listę plików na koncie Dysku Google uwierzytelnionego użytkownika. Zwróć uwagę głównie na 2 rzeczy:
-
Użytkownik musi nie tylko być uwierzytelniony, ale też przyznać aplikacji zakres
https://www.googleapis.com/auth/drive.readonly
, który określasz w atrybucieGoogleScopedAuthorize
. -
Używamy standardowego mechanizmu wstrzykiwania zależności ASP.NET Core 3, aby otrzymać
IGoogleAuthProvider
, którego używamy do uzyskania danych logowania użytkownika.
Kod:
-
Najpierw do kontrolera dodaj 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 prosty widok, który odbiera 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. Zerknij na
HomeController.cs
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests, aby dowiedzieć się, jak:
- Tylko uwierzytelnianie użytkowników, bez konkretnych zakresów
- Funkcja wylogowywania
- Autoryzacja przyrostowa przy użyciu kodu. Powyższy fragment kodu pokazuje przyrostową autoryzację za pomocą atrybutów.
- Sprawdź aktualnie przyznane zakresy
- Sprawdź tokeny dostępu i odśwież
- Wymuś odświeżenie tokena dostępu. Nie musisz robić tego samodzielnie, ponieważ Google.Apis.Auth.AspNetCore3 wykryje, czy token dostępu wygasł czy jest bliski wygaśnięcia, 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 własnej aplikacji klienckiej.
Aplikacja kliencka 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”. Następnie możesz pobrać klucz prywatny. Zapoznaj się z naszym przykładowym kontem usługi za pomocą 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(); } } }
Powyższy przykładowy kod tworzy ServiceAccountCredential
.
Wymagane zakresy zostały ustawione i występuje wywołanie FromCertificate
, które wczytuje klucz prywatny z podanego X509Certificate2
.
Podobnie jak we wszystkich innych przykładach kodu dane logowania są ustawione na HttpClientInitializer
.