OAuth 2.0

Este documento descreve o OAuth 2.0, quando usá-lo, como adquirir IDs do cliente e como usá-la com a biblioteca de cliente da API do Google para .NET.

Protocolo OAuth 2.0

OAuth 2.0 é o protocolo de autorização usado pelas APIs do Google. Leia os links abaixo para se familiarizar com o protocolo:

Adquirir IDs e chaves secretas do cliente

É possível conseguir IDs de clientes e chaves secretas no Console de APIs do Google. Há diferentes tipos de IDs do cliente, Portanto, certifique-se de obter o tipo correto para seu aplicativo:

.

Em cada um dos snippets de código abaixo (exceto o da conta de serviço), você precisa fazer o download dos chave secreta do cliente e armazene-a como client_secrets.json no projeto.

Credenciais

Credenciais do usuário

UserCredential é uma classe auxiliar thread-safe para usar um token de acesso para acessar recursos protegidos. Um token de acesso normalmente expira após 1 hora, Você vai receber um erro se tentar usá-lo.

UserCredential e AuthorizationCodeFlow cuidar da "atualização" automática do token, o que significa simplesmente receber um novo token de acesso. Isso é feito usando um token de atualização de longa duração, que você recebe junto com a token de acesso se você usar o access_type=offline durante o fluxo do código de autorização.

Na maioria dos aplicativos, é aconselhável armazenar os token de acesso da credencial e do token de atualização no armazenamento permanente. Caso contrário, será necessário apresentar ao usuário final página de autorização no navegador a cada hora, já que o acesso token expira uma hora depois de ser recebido.

Para garantir que os tokens de acesso e atualização persistam, você pode fornecer sua própria implementação IDataStore, ou você pode usar uma das seguintes implementações fornecidas pela biblioteca:

  • FileDataStore para .NET garante que a credencial seja persistente em um arquivo.

ServiceAccountCredential

ServiceAccountCredential é semelhante ao UserCredential, mas serve a uma finalidade diferente. O Google OAuth 2.0 oferece suporte a interações de servidor para servidor, como as que ocorrem entre um aplicativo da Web e o Google Cloud Storage. O aplicativo solicitante precisa provar a própria identidade para ter acesso a uma API, e o usuário final não precisa estar envolvido. ServiceAccountCredential armazena uma chave privada, que é usada para assinar uma solicitação e receber um novo token de acesso.

Tanto UserCredential quanto ServiceAccountCredential implementam IConfigurableHttpClientInitializer para que você possa registrar cada um deles como:

  • Um gerenciador de respostas com falha Por isso, ele vai atualizar o token se receber um código de status HTTP 401.
  • Um interceptador para interceptar o Authorization em cada solicitação.

Aplicativos instalados

Exemplo de código usando a API 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();
            ...
        }
    }
}
  
  • Neste exemplo de código, uma nova instância UserCredential é criada chamando o GoogleWebAuthorizationBroker.AuthorizeAsync. Esse método estático recebe o seguinte:

    • A chave secreta do cliente (ou um stream para a chave secreta do cliente).
    • Os escopos necessários.
    • É o identificador do usuário.
    • O token de cancelamento para cancelar uma operação.
    • Um repositório de dados opcional. Se o repositório de dados não for especificado, o padrão será FileDataStore. com uma pasta Google.Apis.Auth padrão. A pasta será criada em Environment.SpecialFolder.ApplicationData.
  • O UserCredential retornado por esse método é definido como um HttpClientInitializer. no BooksService (usando o inicializador). Como explicado acima, UserCredential implementa uma inicializador de cliente HTTP.

  • Observe que, no exemplo de código acima, as informações da chave secreta do cliente são carregadas de um arquivo, mas também é possível fazer o seguinte:

    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"));
          

Confira nossa amostra do Google Livros.

Aplicativos da Web (ASP.NET Core 3)

Suporte das APIs do Google OAuth 2.0 para aplicativos de servidor da Web

O Google.Apis.Auth.AspNetCore3 é a biblioteca recomendada para a maioria Cenários de OAuth 2.0 em aplicativos ASP.NET Core 3. Ele implementa uma política do Google Gerenciador de autenticação OpenIdConnect. Ele dá suporte à autenticação incremental e define uma IGoogleAuthProvider para fornecer credenciais do Google que podem ser usadas com as APIs do Google.

Esta seção descreve como configurar e usar Google.Apis.Auth.AspNetCore3. O código mostrado aqui é baseada Google.Apis.Auth.AspNetCore3.IntegrationTests que é um ASP.NET padrão e totalmente funcional aplicativo Core 3.

Se você quiser acompanhar esta documentação como um tutorial, precisará do seu próprio arquivo ASP.NET. Core 3 e concluir essas etapas como pré-requisito.

Pré-requisitos

  • Instale o Google.Apis.Auth.AspNetCore3.
  • Estamos usando a API Google Drive para que você também precisam instalar Google.Apis.Drive.v3 .
  • Crie um projeto do Google Cloud, caso ainda não tenha um. Seguir estas instruções para fazer isso. Esse será o projeto com o qual seu aplicativo será identificado.
  • Ative a API Google Drive. Para ativar as APIs, siga estas instruções.
  • Crie credenciais de autorização que identificarão seu app para o Google. Seguir estas instruções para criar credenciais de autorização e fazer o download do arquivo client_secrets.json. Dois destaques:
    • Observe que o cabeçalho O tipo precisa ser aplicativo da Web.
    • Para executar este app, o único URI de redirecionamento que você precisa adicionar é https://localhost:5001/signin-oidc:

Configurar seu aplicativo para usar Google.Apis.Auth.AspNetCore3

Google.Apis.Auth.AspNetCore3 está configurado na classe Startup ou semelhante alternativa que você esteja usando. Os seguintes snippets são extraídos Startup.cs no projeto Google.Apis.Auth.AspNetCore3.IntegrationTests.

  • Adicione o código a seguir usando a diretiva para o arquivo Startup.cs.
    using Google.Apis.Auth.AspNetCore3;
  • No método Startup.ConfigureServices, adicione o código a seguir e altere a Os marcadores de posição do ID e da chave secreta do cliente com os valores contidos nos arquivo client_secrets.json. É possível carregar esses valores diretamente do arquivo JSON ou pode armazená-los de outra maneira segura. Dê uma olhada no ClientInfo.Load no Google.Apis.Auth.AspNetCore3.IntegrationTests projeto para obter um exemplo de como carregar esses valores diretamente do arquivo 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};
            });
    }
          
  • No método Startup.Configure, adicione a autenticação do ASP.NET Core 3. e os componentes de middleware de autorização para o pipeline, bem como redirecionamentos HTTPS:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        ...
        app.UseHttpsRedirection();
        ...
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        ...
    }
          

Usar a credencial do usuário para acessar as APIs do Google em nome dele

Agora está tudo pronto para adicionar métodos de ação aos controladores que exigem a credencial do usuário para acessar as APIs do Google em nome deles. O snippet a seguir mostra como listar os arquivos na da conta do Google Drive do usuário autenticado. Note duas coisas principalmente:

  • O usuário não só precisa ser autenticado, mas também ter concedido a permissão escopo https://www.googleapis.com/auth/drive.readonly a seu aplicativo, que especificado pelo atributo GoogleScopedAuthorize.
  • Estamos usando o mecanismo de injeção de dependência padrão do ASP.NET Core 3 para receber uma IGoogleAuthProvider que usamos para receber as credenciais do usuário.

O código:

  • Primeiro, adicione o seguinte usando diretivas para seu controlador.
    using Google.Apis.Auth.AspNetCore3;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Drive.v3;
    using Google.Apis.Services;
          
  • Adicione a ação do controlador da seguinte maneira (e acompanhe-a com uma visualização simples que recebe um 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);
    }
          

E estes são os princípios básicos. Para saber mais, HomeController.cs do projeto Google.Apis.Auth.AspNetCore3.IntegrationTests para descobrir como:

  • Somente autenticação do usuário, sem escopos específicos
  • Funcionalidade de saída
  • Autorização incremental por código. O snippet acima mostra aumentos autorização por meio de atributos.
  • Examinar escopos concedidos atualmente
  • Examinar tokens de acesso e atualização
  • Force a atualização do token de acesso. Observe que você não precisa fazer isso sozinho, Google.Apis.Auth.AspNetCore3 detecta se o token de acesso expirou ou está perto de expirar e o atualizará automaticamente.

Conta de serviço

As APIs do Google também dão suporte Contas de serviço. Diferentemente do cenário em que um aplicativo cliente solicita acesso aos dados de um usuário final, as contas de serviço oferecem acesso aos próprios dados do aplicativo cliente.

Seu aplicativo cliente assina a solicitação para um token de acesso usando uma chave privada baixada no Console de APIs do Google. Depois de criar um novo ID do cliente, escolha uma "Conta de serviço" tipo de aplicativo e, em seguida, poderá fazer o download da chave privada. Confira nossa amostra de conta de serviço usando a 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();
        }
    }
}

O exemplo de código acima cria uma ServiceAccountCredential Os escopos necessários estão definidos e há uma chamada para FromCertificate, que carrega a chave privada do X509Certificate2 fornecido. Como em todos os outros exemplos de código, a credencial é definida como HttpClientInitializer.