In questo documento viene descritto OAuth 2.0, quando utilizzarlo, come acquisire ID client e come utilizzarlo con la libreria client delle API di Google per .NET.
Protocollo OAuth 2.0
OAuth 2.0 è il protocollo di autorizzazione utilizzato dalle API di Google. Dovresti acquisire familiarità con il protocollo leggendo i seguenti link:
Acquisizione di ID client e secret
Puoi recuperare gli ID client e i secret nella Console API di Google. Esistono diversi tipi di ID client, quindi assicurati di ottenere il tipo corretto per la tua applicazione:
- ID client di applicazioni web
- ID client dell'applicazione installata
- ID client dell'account di servizio
Devi scaricare il secret del client e archiviarlo come client_secrets.json
nel progetto in ogni snippet di codice riportato di seguito (tranne l'account di servizio).
Credenziali
Credenziali utente
UserCredential
è una classe helper sicura per i thread che utilizza un token di accesso per accedere alle risorse protette.
Un token di accesso scade in genere dopo un'ora, dopodiché verrà visualizzato un errore se tenti di utilizzarlo.
UserCredential
e
AuthorizationCodeFlow
si occupano dell'"aggiornamento" automatico del token, il che significa semplicemente ottenere un nuovo token di accesso.
Questa operazione viene eseguita utilizzando un token di aggiornamento di lunga durata, che ricevi insieme al
token di accesso se utilizzi il parametro
access_type=offline
durante il flusso del codice di autorizzazione.
Nella maggior parte delle applicazioni, è consigliabile archiviare il token di accesso e il token di aggiornamento delle credenziali in uno spazio di archiviazione permanente. In caso contrario, dovrai mostrare all'utente finale una pagina di autorizzazione nel browser ogni ora, perché il token di accesso scade un'ora dopo che l'hai ricevuto.
Per assicurarti che i token di accesso e di aggiornamento permanano,
puoi fornire la tua implementazione di
IDataStore
oppure utilizzare una delle seguenti implementazioni fornite dalla libreria:
-
FileDataStore
per .NET assicura che la credenziale sia permanente in un file.
ServiceAccountCredential
ServiceAccountCredential
è simile a UserCredential
, ma ha una finalità diversa.
Google OAuth 2.0 supporta le interazioni server-server, come quelle tra un'applicazione web e Google Cloud Storage.
L'applicazione richiedente deve dimostrare la propria identità per ottenere l'accesso a un'API e l'utente finale non deve essere coinvolto.
ServiceAccountCredential
archivia una chiave privata, che viene utilizzata per firmare una richiesta per ricevere un nuovo token di accesso.
Sia UserCredential
che ServiceAccountCredential
implementano
IConfigurableHttpClientInitializer
quindi puoi registrare ciascuno di questi dati come:
- Un gestore di risposte non riuscite, che aggiornerà il token se riceve un codice di stato HTTP
401
. - Un intercettatore, per intercettare l'intestazione
Authorization
in ogni richiesta.
Applicazioni installate
Esempio di codice tramite l'API Libri:
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(); ... } } }
-
In questo codice di esempio viene creata una nuova istanza
UserCredential
chiamando il metodoGoogleWebAuthorizationBroker.AuthorizeAsync
. Questo metodo statico ottiene quanto segue:- Il client secret (o uno stream per il client secret).
- Gli ambiti obbligatori.
- L'identificatore utente.
- Il token di annullamento per annullare un'operazione.
- Un datastore facoltativo. Se il datastore non è specificato, il valore predefinito è un
FileDataStore
con una cartellaGoogle.Apis.Auth
predefinita. La cartella viene creata inEnvironment.SpecialFolder.ApplicationData
.
-
L'elemento
UserCredential
restituito da questo metodo è impostato comeHttpClientInitializer
suBooksService
(utilizzando l'inizializzatore). Come spiegato in precedenza,UserCredential
implementa un inizializzatore client HTTP. -
Tieni presente che nel codice campione sopra riportato vengono caricate le informazioni del client secret da un file, ma puoi anche:
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"));
Dai un'occhiata all'esempio di Libri.
Applicazioni web (ASP.NET Core 3)
Le API di Google supportano OAuth 2.0 per le applicazioni server web.
Google.Apis.Auth.AspNetCore3 è la libreria consigliata da utilizzare per la maggior parte degli scenari OAuth 2.0 basati su Google nelle applicazioni ASP.NET Core 3. Implementa un gestore di autenticazione OpenIdConnect
specifico di Google. Supporta l'autenticazione incrementale e definisce un IGoogleAuthProvider
iniettabile per fornire le credenziali Google che possono essere utilizzate con le API di Google.
Questa sezione descrive come configurare e utilizzare Google.Apis.Auth.AspNetCore3. Il codice mostrato qui si basa su Google.Apis.Auth.AspNetCore3.IntegrationTests, un'applicazione ASP.NET Core 3 standard completamente funzionante.
Se vuoi seguire questa documentazione come tutorial, avrai bisogno della tua applicazione ASP.NET Core 3 e di completare questi passaggi come prerequisito.
Prerequisiti
- Installa il pacchetto Google.Apis.Auth.AspNetCore3.
- Stiamo utilizzando l'API Google Drive, quindi devi anche installare il pacchetto Google.Apis.Drive.v3.
- Se non ne hai già uno, crea un progetto Google Cloud. A tale scopo, segui queste istruzioni. Questo sarà il progetto con cui viene identificata la tua app.
- Assicurati di attivare l'API Google Drive. Per abilitare le API, segui queste istruzioni.
-
Crea credenziali di autorizzazione che identifichino la tua app su Google. Segui
queste istruzioni per creare le credenziali di autorizzazione e scaricare il
file
client_secrets.json
. Due caratteristiche principali:- Nota che il tipo di credenziali deve essere Applicazione web.
- Per eseguire questa app, l'unico URI di reindirizzamento che devi aggiungere è
https://localhost:5001/signin-oidc
.
Configura la tua applicazione per l'utilizzo di Google.Apis.Auth.AspNetCore3
Google.Apis.Auth.AspNetCore3 è configurato nella classe Startup
o in un'alternativa simile che potresti utilizzare. I seguenti snippet vengono estratti da
Startup.cs
nel progetto Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Aggiungi quanto segue utilizzando l'istruzione al file
Startup.cs
.using Google.Apis.Auth.AspNetCore3;
-
Nel metodo
Startup.ConfigureServices
aggiungi il codice seguente, modifica l'ID client e i segnaposto Client Secret con i valori contenuti nel fileclient_secrets.json
. Puoi caricare questi valori direttamente dal file JSON oppure puoi archiviarli in qualsiasi altro modo sicuro. Dai un'occhiata al metodoClientInfo.Load
nel progetto Google.Apis.Auth.AspNetCore3.IntegrationTests per un esempio di come caricare questi valori direttamente dal file 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}; }); }
-
Nel metodo
Startup.Configure
, assicurati di aggiungere alla pipeline i componenti middleware di autenticazione e autorizzazione di ASP.NET Core 3, nonché i reindirizzamenti HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Utilizzare le credenziali dell'utente per accedere alle API di Google per conto degli utenti
Ora puoi aggiungere metodi di azione ai controller che richiedono le credenziali utente per accedere alle API di Google per loro conto. Il seguente snippet mostra come elencare i file dell'account Google Drive autenticato dell'utente. Osserva principalmente due aspetti:
-
L'utente non solo deve essere autenticato, ma deve anche aver concesso l'ambito
https://www.googleapis.com/auth/drive.readonly
alla tua applicazione, che specifichi tramite l'attributoGoogleScopedAuthorize
. -
Stiamo utilizzando il meccanismo di iniezione delle dipendenze standard di ASP.NET Core 3 per ricevere un
IGoogleAuthProvider
che utilizziamo per ottenere le credenziali dell'utente.
Il codice:
-
Per prima cosa, aggiungi le istruzioni seguenti utilizzando le istruzioni al controller.
using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;
-
Aggiungi l'azione del controller come segue (e accompagnala con una visualizzazione semplice che riceve un modello
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); }
E queste sono le nozioni di base. Puoi dare un'occhiata a
HomeController.cs
dal progetto Google.Apis.Auth.AspNetCore3.IntegrationTests
per scoprire come ottenere:
- Solo autenticazione utente, senza ambiti specifici
- Funzionalità di disconnessione
- Autorizzazione incrementale tramite codice. Lo snippet riportato sopra mostra l'autorizzazione incrementale tramite attributi.
- Esamina gli ambiti attualmente concessi
- Esaminare i token di accesso e di aggiornamento
- Forza l'aggiornamento del token di accesso. Tieni presente che non devi farlo personalmente perché Google.Apis.Auth.AspNetCore3 rileverà se il token di accesso è scaduto o sta per scadere e lo aggiornerà automaticamente.
Applicazioni web (ASP.NET MVC)
Le API di Google supportano OAuth 2.0 per le applicazioni server web.
Per eseguire correttamente il codice seguente, devi prima aggiungere un URI di reindirizzamento al tuo progetto nella console API di Google.
Poiché utilizzerai FlowMetadata
e le relative impostazioni predefinite,
imposta l'URI di reindirizzamento su
your_site/AuthCallback/IndexAsync
.
Per trovare gli URI di reindirizzamento delle tue credenziali OAuth 2.0:
- Apri la pagina Credenziali nella console API.
- Se non lo hai già fatto, crea le tue credenziali OAuth 2.0 facendo clic su Crea credenziali > ID client OAuth.
- Dopo aver creato le credenziali, visualizza o modifica gli URL di reindirizzamento facendo clic sull'ID client (per un'applicazione web) nella sezione ID client OAuth 2.0.
Dopo aver creato un nuovo progetto di applicazione web nel tuo IDE, aggiungi il pacchetto Google.Apis
NuGet corretto per Drive, YouTube o l'altro servizio che vuoi utilizzare. Quindi, aggiungi il pacchetto Google.Apis.Auth.MVC.
Il codice che segue mostra un'applicazione MSP ASP.NET che esegue query su un servizio API di Google.
-
Aggiungi la tua implementazione di
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
è una classe astratta che contiene la tua logica per recuperare l'identificatore utente e laIAuthorizationCodeFlow
che stai utilizzando.Nel codice di esempio sopra riportato, viene creata una nuova
GoogleAuthorizationCodeFlow
con gli ambiti giusti, i client secret e il datastore. Valuta la possibilità di aggiungere la tua implementazione diIDataStore
, ad esempio potresti scriverne una che utilizzaEntityFramework
. -
Implementare il controller che utilizza un servizio API di Google.
Nel seguente esempio viene utilizzato il tipo
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); } } } }
-
Implementa il tuo controller di callback. L'implementazione dovrebbe essere simile alla seguente:
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(); } } } }
Account di servizio
Le API di Google supportano anche gli account di servizio. A differenza dello scenario in cui un'applicazione client richiede l'accesso ai dati dell'utente finale, gli account di servizio forniscono l'accesso ai dati dell'applicazione client.
L'applicazione client firma la richiesta di un token di accesso utilizzando una chiave privata scaricata dalla Google API Console. Dopo aver creato un nuovo ID client, devi scegliere un tipo di applicazione "Account di servizio" per poi scaricare la chiave privata. Dai un'occhiata all'esempio dell'account di servizio utilizzando l'API Google Plus.
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(); } } }
Il codice campione sopra creato crea una
ServiceAccountCredential
.
Gli ambiti obbligatori sono impostati ed è presente una chiamata al FromCertificate
, che carica la chiave privata dal X509Certificate2
specificato.
Come in tutti gli altri codici di esempio, la credenziale è impostata su HttpClientInitializer
.