W tym dokumencie opisano protokół OAuth 2.0 oraz informacje o tym, kiedy go używać, jak pobierać identyfikatory klientów i jak używać go z biblioteką interfejsu API Google dla domeny .NET.
Protokół OAuth 2.0
OAuth 2.0 to protokół autoryzacji używany przez interfejsy API Google. Aby zapoznać się z tym protokołem, przeczytaj te linki:
Pozyskiwanie identyfikatorów i obiektów tajnych klienta
Identyfikatory i tajne kody klienta możesz pobrać z konsoli Google API. Istnieją różne typy identyfikatorów klientów, dlatego dopilnuj, aby otrzymać odpowiedni typ aplikacji:
- Identyfikatory klientów aplikacji internetowych
- Identyfikatory klientów zainstalowanych aplikacji
- Identyfikatory klientów konta usługi
W każdym z poniższych fragmentów kodu (z wyjątkiem konta usługi jeden) musisz pobrać tajny klucz klienta i zapisać go w projekcie jako client_secrets.json
.
Dane uwierzytelniające
Dane logowania użytkownika
UserCredential
to klasa pomocna w wątek, która służy do korzystania z tokena dostępu do chronionych zasobów.
Token dostępu zazwyczaj wygasa po godzinie i po tym czasie pojawi się błąd, jeśli spróbujesz go użyć.
UserCredential
i AuthorizationCodeFlow
zajmują się automatycznym „odświeżaniem”, co oznacza po prostu uzyskanie nowego tokena dostępu.
W tym celu używany jest długotrwały token odświeżania, który otrzymujesz wraz z tokenem dostępu, jeśli używasz parametru access_type=offline
podczas procesu kodu autoryzacji.
W większości aplikacji zaleca się przechowywanie danych logowania i tokena odświeżania w pamięci trwałej. W przeciwnym razie musisz wyświetlać użytkownikowi stronę autoryzacji w przeglądarce co godzinę, ponieważ token dostępu wygasa po upływie godziny od jego otrzymania.
Aby mieć pewność, że tokeny dostępu i odświeżania się nie zmienią, możesz wprowadzić własną implementację IDataStore
lub użyć jednej z tych implementacji dostępnych w bibliotece:
-
FileDataStore
w przypadku pliku .NET zapewnia, że dane logowania pozostaną w pliku.
Dane logowania konta usługi
ServiceAccountCredential
jest podobny do UserCredential
, ale służy do innego celu.
Google OAuth 2.0 obsługuje interakcje między serwerami, np. między aplikacją internetową a Google Cloud Storage.
Aby uzyskać dostęp do interfejsu API, aplikacja żądająca musi udowodnić swoją tożsamość, a użytkownik nie musi w tym uczestniczyć.
ServiceAccountCredential
przechowuje klucz prywatny, który służy do podpisywania prośby o nowy token dostępu.
Zarówno UserCredential
, jak i ServiceAccountCredential
implementują IConfigurableHttpClientInitializer
, aby zarejestrować każdą z nich jako:
- Niepowodzenie modułu obsługi odpowiedzi, więc odświeży token, jeśli otrzyma kod stanu HTTP
401
. - Element przechwytywania, który przechwytuje nagłówek
Authorization
przy każdym żądaniu.
Zainstalowane aplikacje
Przykładowy kod za pomocą 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 zostanie utworzona nowa instancja
UserCredential
przez wywołanie metodyGoogleWebAuthorizationBroker.AuthorizeAsync
. Ta metoda statyczna uzyskuje:- Tajny klucz klienta (lub strumień do tajnego klucza klienta).
- Wymagane zakresy.
- Identyfikator użytkownika.
- Token anulowania anulowania operacji.
- Opcjonalny magazyn danych. Jeśli magazyn danych nie został określony, domyślną wartością jest
FileDataStore
z domyślnym folderemGoogle.Apis.Auth
. Folder zostanie utworzony w aplikacjiEnvironment.SpecialFolder.ApplicationData
.
-
Metoda
UserCredential
, która jest zwracana przez tę metodę, jest ustawiana jakoHttpClientInitializer
wBooksService
(za pomocą inicjatora). Jak wyjaśniliśmy powyżej,UserCredential
implementuje inicjator klienta HTTP. -
W powyższym przykładowym kodzie informacje o kliencie klienta są ładowane 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"));
Przejrzyj próbkę książek.
Aplikacje internetowe (ASP.NET Core 3)
Interfejsy API Google obsługują protokół OAuth 2.0 dla aplikacji internetowych.
Google.Apis.Auth.AspNetCore3 to zalecana biblioteka, która jest używana w większości scenariuszy dotyczących protokołu OAuth 2.0 opartych na usługach Google w aplikacjach ASP.NET Core 3. Implementuje moduł obsługi uwierzytelniania OpenIdConnect
w Google. Obsługuje uwierzytelnianie przyrostowe i definiuje wstrzyknięty kod IGoogleAuthProvider
do przesyłania danych logowania Google, których można używać z interfejsami API Google.
W tej sekcji opisano, jak skonfigurować Google.Apis.Auth.AspNetCore3 i jak z niej korzystać. Podany tu kod jest oparty na: Google.Apis.Auth.AspNetCore3.IntegrationTests, która jest w pełni sprawną, standardową aplikacją ASP.NET Core 3.
Jeśli chcesz wykonać instrukcje zgodnie z tą dokumentacją, musisz mieć własną aplikację ASP.NET Core 3 i wykonać te czynności wstępne.
Wymagania wstępne
- Zainstaluj pakiet Google.Apis.Auth.AspNetCore3.
- Używamy interfejsu API Dysku Google, dlatego 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. Będzie to projekt identyfikujący Twoją aplikację.
- Włącz interfejs Google Drive API. Aby włączyć interfejsy API, postępuj zgodnie z tymi instrukcjami.
-
Utwórz dane logowania, które będą identyfikować Twoją aplikację w Google. Wykonaj te instrukcje, aby utworzyć dane logowania i pobrać plik
client_secrets.json
. Dwie ważne informacje:- Zwróć uwagę, że dane logowania muszą mieć typ Aplikacja internetowa.
- Aby uruchomić tę aplikację, wystarczy podać identyfikator URI przekierowania:
https://localhost:5001/signin-oidc
.
Konfigurowanie aplikacji pod kątem korzystania z Google.Apis.Auth.AspNetCore3
Plik Google.Apis.Auth.AspNetCore3 jest skonfigurowany w klasie Startup
lub podobnej metod, której możesz używać. Poniższe fragmenty są wyodrębnione z Startup.cs
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Dodaj do pliku
Startup.cs
poniższą dyrektywę.using Google.Apis.Auth.AspNetCore3;
-
W metodzie
Startup.ConfigureServices
dodaj następujący kod zastępczy Client-ID i obiekty tajne klucza klienta w wartościach z plikuclient_secrets.json
. Wartości możesz wczytywać bezpośrednio z pliku JSON lub w inny sposób zabezpieczony. Przykład metody wczytywania tych wartości bezpośrednio z pliku JSON znajdziesz w projekcieClientInfo.Load
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests.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 autoryzacji ASP.NET Core 3 oraz przekierowania HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Używaj danych logowania użytkownika, aby uzyskiwać dostęp do interfejsów API Google w ich imieniu
Możesz teraz dodawać metody działania do kontrolerów, które wymagają danych logowania użytkownika do korzystania z interfejsów API Google w ich imieniu. Poniższy fragment przedstawia, jak wyświetlić listę plików na uwierzytelnionym koncie Dysku Google. Zwróć uwagę przede wszystkim na te kwestie:
-
Użytkownik nie tylko musi zostać uwierzytelniony, ale musi też przyznać aplikacji zakres
https://www.googleapis.com/auth/drive.readonly
określony w atrybucieGoogleScopedAuthorize
. -
Do uzyskania danych logowania użytkownika używamy
IGoogleAuthProvider
standardowego mechanizmu wstrzykiwania zależności ASP.NET Core 3'.
Kod:
-
Najpierw dodaj w kontrolerze te polecenia:
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 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); }
A to podstawy. Aby dowiedzieć się, co możesz osiągnąć, zapoznaj się z narzędziem HomeController.cs
w projekcie Google.Apis.Auth.AspNetCore3.IntegrationTests:
- Tylko uwierzytelnianie użytkownika, bez określonych zakresów
- Funkcja wylogowywania
- Autoryzacja przyrostowa za pomocą kodu. Zwróć uwagę, że fragment kodu powyżej zawiera przyrostową autoryzację według atrybutów.
- Badanie obecnie przyznanych zakresów
- Badanie dostępu i tokenów odświeżania
- Wymuś odświeżenie tokena dostępu. Nie musisz robić tego samodzielnie, bo Google.Apis.Auth.AspNetCore3 wykryje, czy token dostępu wygasł lub niedługo wygaśnie – i automatycznie się odświeży.
Aplikacje internetowe (ASP.NET MVC)
Interfejsy API Google obsługują protokół OAuth 2.0 dla aplikacji internetowych.
Aby uruchomić poniższy kod, musisz najpierw dodać do projektu identyfikator URI przekierowania w konsoli Google API.
Ponieważ będziesz używać atrybutu FlowMetadata
i jego ustawień domyślnych, ustaw identyfikator URI przekierowania na wartość your_site/AuthCallback/IndexAsync
.
Aby znaleźć identyfikatory URI przekierowania dla danych logowania OAuth 2.0, wykonaj te czynności:
- Otwórz stronę Dane logowania w konsoli interfejsu API.
- Jeśli nie utworzono jeszcze danych logowania OAuth 2.0, kliknij Utwórz dane logowania OAuth 2.0.
- Po utworzeniu danych logowania możesz wyświetlić lub edytować przekierowania, klikając identyfikator klienta (w przypadku aplikacji internetowej) w sekcji Identyfikatory klienta OAuth 2.0.
Po utworzeniu w projekcie IDE nowego projektu aplikacji internetowej dodaj odpowiedni pakiet Google.Apis
NuGet dla Dysku, YouTube lub innej usługi, z której chcesz korzystać. Następnie dodaj pakiet Google.Apis.Auth.MVC.
Poniższy kod pokazuje aplikację ASP.NET MVC, która wysyła zapytanie do usługi interfejsu API Google.
-
Dodaj własną implementację tagu
FlowMetadata
.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
to abstrakcyjna klasa zawierająca Twoją logikę pobierania identyfikatora użytkownika i używanegoIAuthorizationCodeFlow
.W powyższym przykładowym kodzie zostanie utworzony nowy element
GoogleAuthorizationCodeFlow
z odpowiednimi zakresami, obiektami tajnymi klienta i magazynem danych. Możesz dodać własną implementację taguIDataStore
, na przykład możesz użyć właściwościEntityFramework
. -
Zaimplementuj własny kontroler, który korzysta z usługi interfejsu API Google.
Ta przykład używa
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); } } } }
-
Zaimplementuj własny kontroler wywołania zwrotnego. Implementacja powinna wyglądać mniej więcej tak:
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(); } } } }
Konto usługi
Interfejsy API Google obsługują też konta usługi. Inaczej niż w przypadku scenariusza, w którym aplikacja kliencka prosi o dostęp do danych użytkownika końcowego, konta usługi zapewniają dostęp do takich danych.
Aplikacja kliencka podpisuje żądanie tokena dostępu przy użyciu klucza prywatnego pobranego z Konsoli interfejsów API Google. Po utworzeniu nowego identyfikatora klienta wybierz typ aplikacji „Konto usługi”, a następnie pobierz klucz prywatny. Zapoznaj się z 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 są ustawione zakresy i wywołanie FromCertificate
, które wczytuje klucz prywatny z podanego X509Certificate2
.
Tak jak we wszystkich innych przykładowych kodach, dane logowania są ustawione na HttpClientInitializer
.