En este documento, se describe OAuth 2.0, cuándo usarlo, cómo adquirir los ID de cliente y cómo usarlo con la biblioteca cliente de las API de Google para .NET.
Protocolo OAuth 2.0
OAuth 2.0 es el protocolo de autorización que usan las APIs de Google. Deberías familiarizarte con el protocolo; para ello, lee los siguientes enlaces:
Adquiere IDs de cliente y secretos
Puedes obtener IDs de cliente y secretos en la Consola de APIs de Google. Existen diferentes tipos de ID de cliente, así que asegúrate de obtener el tipo correcto para tu aplicación:
- IDs de cliente de aplicación web
- IDs de cliente de la aplicación instalada
- IDs de cliente de la cuenta de servicio
En cada uno de los fragmentos de código que aparecen a continuación (excepto el de la cuenta de servicio), debes descargar el
secreto del cliente y almacenarlo como client_secrets.json
en tu proyecto.
Credenciales
Credenciales de usuario
UserCredential
es una clase de ayuda segura para subprocesos para usar un token de acceso a fin de acceder a recursos protegidos.
Por lo general, los tokens de acceso vencen después de 1 hora. Si intentas usarlos, aparecerá un error.
UserCredential
y AuthorizationCodeFlow
se encargan de "actualizar" automáticamente el token, lo que simplemente significa obtener un token de acceso nuevo.
Para ello, se usa un token de actualización de larga duración, que recibes junto con el token de acceso si usas el parámetro access_type=offline
durante el flujo de código de autorización.
En la mayoría de las aplicaciones, es recomendable almacenar el token de acceso y el token de actualización de la credencial en el almacenamiento persistente. De lo contrario, deberás presentar al usuario final una página de autorización en el navegador cada hora, ya que el token de acceso vence una hora después de haberlo recibido.
Para asegurarte de que el acceso y los tokens de actualización persistan, puedes proporcionar tu propia implementación de IDataStore
, o bien puedes usar una de las siguientes implementaciones que proporciona la biblioteca:
-
FileDataStore
para .NET garantiza que la credencial sea persistente en un archivo.
ServiceAccountCredential
ServiceAccountCredential
es similar a UserCredential
, pero cumple un propósito diferente.
Google OAuth 2.0 es compatible con las interacciones servidor a servidor, como las que se producen entre una aplicación web y Google Cloud Storage.
La aplicación solicitante debe probar su propia identidad para obtener acceso a una API, sin la necesidad de involucrar al usuario final.
ServiceAccountCredential
almacena una clave privada, que se usa para firmar una solicitud a fin de obtener un nuevo token de acceso.
Tanto UserCredential
como ServiceAccountCredential
implementan IConfigurableHttpClientInitializer
, por lo que puedes registrar cada uno de ellos de la siguiente manera:
- Un controlador de respuestas con errores, por lo que actualizará el token si recibe un código de estado HTTP
401
. - Un interceptor para interceptar el encabezado
Authorization
en cada solicitud.
Aplicaciones instaladas
Código de muestra con la API de Books:
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(); ... } } }
-
En este código de muestra, se crea una instancia de
UserCredential
nueva mediante una llamada al métodoGoogleWebAuthorizationBroker.AuthorizeAsync
. Con este método estático, se obtiene lo siguiente:- El secreto del cliente (o una transmisión al secreto del cliente).
- Los permisos necesarios.
- El identificador de usuario.
- El token de cancelación para cancelar una operación.
- Es un almacén de datos opcional. Si no se especifica el almacén de datos, el valor predeterminado será un objeto
FileDataStore
con una carpetaGoogle.Apis.Auth
predeterminada. La carpeta se creó enEnvironment.SpecialFolder.ApplicationData
.
-
El
UserCredential
que muestra este método se establece comoHttpClientInitializer
enBooksService
(mediante el inicializador). Como se explicó anteriormente,UserCredential
implementa un inicializador de cliente HTTP. -
Ten en cuenta que, en el código de muestra anterior, la información del secreto del cliente se carga desde un archivo, pero también puedes hacer lo siguiente:
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"));
Consulta nuestra muestra de libros.
Aplicaciones web (ASP.NET Core 3)
Las APIs de Google admiten OAuth 2.0 para aplicaciones de servidor web.
Google.Apis.Auth.AspNetCore3 es la biblioteca recomendada para la mayoría de los casos de OAuth 2.0 con base en Google en aplicaciones de ASP.NET Core 3. Implementa un controlador de autenticación OpenIdConnect
específico de Google. Admite la autenticación incremental y define un IGoogleAuthProvider
insertable para proporcionar credenciales de Google que se puedan usar con las APIs de Google.
En esta sección, se describe cómo configurar y usar Google.Apis.Auth.AspNetCore3. El código que se muestra aquí se basa en Google.Apis.Auth.AspNetCore3.IntegrationTests, que es una aplicación ASP.NET Core 3 estándar y totalmente funcional.
Si quieres seguir esta documentación como instructivo, necesitarás tu propia aplicación de ASP.NET Core 3 y completar estos pasos como requisito previo.
Requisitos previos
- Instala el paquete Google.Apis.Auth.AspNetCore3.
- Como usamos la API de Google Drive, también deberás instalar el paquete Google.Apis.Drive.v3.
- Crea un proyecto de Google Cloud si aún no tienes uno. Para hacerlo, sigue estas instrucciones. Este será el proyecto con el que se identifica tu app.
- Asegúrate de habilitar la API de Google Drive. Para habilitar las APIs, sigue estas instrucciones.
-
Crea credenciales de autorización que identifiquen tu app ante Google. Sigue
estas instrucciones para crear credenciales de autorización y descargar el archivo
client_secrets.json
. Dos aspectos destacados:- Ten en cuenta que el tipo de credenciales debe ser Aplicación web.
- Para ejecutar esta app, el único URI de redireccionamiento que debes agregar es
https://localhost:5001/signin-oidc
.
Configura tu aplicación para utilizar Google.Apis.Auth.AspNetCore3
Google.Apis.Auth.AspNetCore3 se configura en la clase Startup
o una alternativa similar que puedas estar usando. Los siguientes fragmentos se extraen de
Startup.cs
en el proyecto Google.Apis.Auth.AspNetCore3.IntegrationTests.
-
Agrega lo siguiente con la directiva a tu archivo
Startup.cs
.using Google.Apis.Auth.AspNetCore3;
-
En el método
Startup.ConfigureServices
, agrega el siguiente código y cambia los marcadores de posición del ID de cliente y del secreto del cliente con los valores incluidos en el archivoclient_secrets.json
. Puedes cargar estos valores directamente desde el archivo JSON o almacenarlos de cualquier otra manera segura. Observa el métodoClientInfo.Load
en el proyecto Google.Apis.Auth.AspNetCore3.IntegrationTests para obtener un ejemplo de cómo cargar estos valores directamente desde el archivo 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}; }); }
-
En el método
Startup.Configure
, asegúrate de agregar componentes de middleware de autenticación y autorización de ASP.NET Core 3 a la canalización, así como redireccionamientos HTTPS:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Usar la credencial de usuario para acceder a las APIs de Google en su nombre
Ahora puedes agregar métodos de acción a tus controladores que requieran la credencial de usuario para acceder a las APIs de Google en su nombre. En el siguiente fragmento, se muestra cómo enumerar los archivos de la cuenta de Google Drive del usuario autenticado. Presta atención principalmente a dos cosas:
-
No solo el usuario debe estar autenticado, sino que también debe haber otorgado el alcance
https://www.googleapis.com/auth/drive.readonly
a tu aplicación, que especificas mediante el atributoGoogleScopedAuthorize
. -
Usamos el mecanismo de inserción de dependencias estándar de ASP.NET Core 3 para recibir una
IGoogleAuthProvider
que usamos para obtener las credenciales del usuario.
El código:
-
Primero, agrega lo siguiente usando directivas para tu controlador.
using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;
-
Agrega la acción del controlador de la siguiente manera (y acompáñala con una vista simple que reciba un modelo
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); }
Y estos son los conceptos básicos. Puedes consultar
HomeController.cs
del proyecto Google.Apis.Auth.AspNetCore3.IntegrationTests para averiguar cómo puedes lograr lo siguiente:
- Solo autenticación de usuario, sin permisos específicos
- Función para salir de la cuenta
- Autorización incremental mediante código. Ten en cuenta que el fragmento anterior muestra la autorización incremental mediante atributos.
- Examina los permisos otorgados actualmente
- Examina el acceso y los tokens de actualización
- Fuerza la actualización del token de acceso. Ten en cuenta que no tienes que hacerlo tú mismo, ya que Google.Apis.Auth.AspNetCore3 detectará si el token de acceso venció o está a punto de hacerlo y lo actualizará automáticamente.
Cuenta de servicio
Las APIs de Google también admiten cuentas de servicio. A diferencia de la situación en la que una aplicación cliente solicita acceso a los datos de un usuario final, las cuentas de servicio proporcionan acceso a los datos de la aplicación cliente.
La aplicación cliente firma la solicitud de un token de acceso con una clave privada descargada desde la Consola de API de Google. Después de crear un ID de cliente nuevo, debes elegir un tipo de aplicación “Cuenta de servicio” y, luego, poder descargar la clave privada. Consulta nuestra muestra de cuenta de servicio con la API de 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(); } } }
El código de muestra anterior crea un ServiceAccountCredential
.
Se configuraron los permisos necesarios y hay una llamada a FromCertificate
, que carga la clave privada de un X509Certificate2
determinado.
Al igual que en todos los demás códigos de muestra, la credencial se establece como HttpClientInitializer
.