ОАут 2.0

В этом документе описывается OAuth 2.0, когда его использовать, как получать идентификаторы клиентов и как использовать его с клиентской библиотекой API Google для .NET.

Протокол OAuth 2.0

OAuth 2.0 — это протокол авторизации, используемый API Google. С протоколом вам следует ознакомиться, прочитав следующие ссылки:

Получите идентификаторы и секреты клиентов

Вы можете получить идентификаторы клиентов и секреты в консоли Google API . Существуют разные типы идентификаторов клиентов, поэтому обязательно выберите правильный тип для вашего приложения:

В каждом из показанных фрагментов кода (кроме учетной записи службы) вам необходимо загрузить секрет клиента и сохранить его как client_secrets.json в своем проекте.

Реквизиты для входа

Учетные данные пользователя

UserCredential — это потокобезопасный вспомогательный класс для использования токена доступа для доступа к защищенным ресурсам. Срок действия токена доступа обычно истекает через 1 час, после чего вы получите сообщение об ошибке, если попытаетесь его использовать.

UserCredential и AuthorizationCodeFlow автоматически «обновляют» токен, что означает получение нового токена доступа. Это делается с помощью долгоживущего токена обновления, который вы получаете вместе с токеном доступа, если используете параметр access_type=offline во время потока кода авторизации.

В большинстве приложений рекомендуется хранить токен доступа к учетным данным и токен обновления в постоянном хранилище. В противном случае вам придется каждый час предоставлять конечному пользователю страницу авторизации в браузере, поскольку срок действия токена доступа истекает через час после его получения.

Чтобы гарантировать сохранение токенов доступа и обновления, вы можете предоставить собственную реализацию IDataStore или использовать одну из следующих реализаций, предоставляемых библиотекой:

  • FileDataStore для .NET гарантирует, что учетные данные будут сохранены в файле.

Сервисаккаунткредентиал

ServiceAccountCredential похож на UserCredential , но служит другой цели. Google OAuth 2.0 поддерживает взаимодействие между серверами, например между веб-приложением и облачным хранилищем Google. Запрашивающее приложение должно подтвердить свою личность, чтобы получить доступ к API, причем участие конечного пользователя не обязательно. ServiceAccountCredential хранит закрытый ключ, который используется для подписи запроса на получение нового токена доступа.

И UserCredential , и ServiceAccountCredential реализуют IConfigurableHttpClientInitializer поэтому вы можете зарегистрировать каждый из них как:

  • Обработчик неудачного ответа, поэтому он обновит токен, если получит код состояния HTTP 401 .
  • Перехватчик, перехватывающий заголовок Authorization при каждом запросе.

Установленные приложения

Пример кода с использованием 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();             ...         }     } }   
  • В этом примере кода новый экземпляр UserCredential создается путем вызова метода GoogleWebAuthorizationBroker.AuthorizeAsync . Этот статический метод получает следующее:

    • Секрет клиента (или поток секрета клиента).
    • Необходимые объемы.
    • Идентификатор пользователя.
    • Токен отмены для отмены операции.
    • Дополнительное хранилище данных. Если хранилище данных не указано, по умолчанию используется FileDataStore с папкой Google.Apis.Auth по умолчанию. Папка создается в Environment.SpecialFolder.ApplicationData .
  • UserCredential , возвращаемый этим методом, устанавливается как HttpClientInitializer в BooksService (с использованием инициализатора). Как объяснялось ранее, UserCredential реализует инициализатор HTTP-клиента .

  • Обратите внимание, что в примере кода секретная информация клиента загружается из файла, но вы также можете сделать следующее:

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

Взгляните на наш образец книг .

Веб-приложения (ASP.NET Core 3)

API Google поддерживают OAuth 2.0 для приложений веб-сервера .

Google.Apis.Auth.AspNetCore3 — это рекомендуемая библиотека для большинства сценариев OAuth 2.0 на базе Google в приложениях ASP.NET Core 3. Он реализует обработчик аутентификации OpenIdConnect специфичный для Google. Он поддерживает инкрементную аутентификацию и определяет внедряемый IGoogleAuthProvider для предоставления учетных данных Google, которые можно использовать с API Google.

В этом разделе описывается, как настроить и использовать Google.Apis.Auth.AspNetCore3. Показанный здесь код основан на Google.Apis.Auth.AspNetCore3.IntegrationTests , который представляет собой полностью рабочее стандартное приложение ASP.NET Core 3.

Если вы хотите следовать этой документации в качестве учебного пособия, вам понадобится собственное приложение ASP.NET Core 3 и выполнение этих шагов в качестве предварительного условия.

Предварительные условия

  • Установите пакет Google.Apis.Auth.AspNetCore3 .
  • Мы используем API Google Диска , поэтому вам также потребуется установить пакет Google.Apis.Drive.v3 .
  • Создайте проект Google Cloud, если у вас его еще нет. Для этого следуйте этим инструкциям . Это будет проект, с которым идентифицируется ваше приложение.
  • Обязательно включите API Google Диска. Чтобы включить API, следуйте этим инструкциям .
  • Создайте учетные данные авторизации, которые будут идентифицировать ваше приложение в Google. Следуйте этим инструкциям , чтобы создать учетные данные для авторизации и загрузить файл client_secrets.json . Два основных момента:
    • Обратите внимание, что тип учетных данных должен быть «Веб-приложение» .
    • Для запуска этого приложения вам нужно добавить единственный URI перенаправления — https://localhost:5001/signin-oidc .

Настройте свое приложение для использования Google.Apis.Auth.AspNetCore3.

Google.Apis.Auth.AspNetCore3 настраивается в классе Startup или аналогичной альтернативе, которую вы можете использовать. Следующие фрагменты извлечены из Startup.cs в проекте Google.Apis.Auth.AspNetCore3.IntegrationTests.

  • Добавьте следующую директиву using в файл Startup.cs .
    using Google.Apis.Auth.AspNetCore3;
  • В методе Startup.ConfigureServices добавьте следующий код, заменяя заполнители Client ID и Client Secret значениями, содержащимися в файле client_secrets.json . Вы можете загрузить эти значения непосредственно из файла JSON или сохранить их любым другим безопасным способом. Взгляните на метод ClientInfo.Load в проекте Google.Apis.Auth.AspNetCore3.IntegrationTests, чтобы увидеть пример загрузки этих значений непосредственно из файла 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};         }); }       
  • В методе Startup.Configure обязательно добавьте в конвейер компоненты промежуточного программного обеспечения аутентификации и авторизации ASP.NET Core 3, а также перенаправления HTTPS:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {     ...     app.UseHttpsRedirection();     ...      app.UseAuthentication();     app.UseAuthorization();      ... }       

Используйте учетные данные пользователя для доступа к API Google от его имени.

Теперь вы готовы добавить в свои контроллеры методы действий, которым требуются учетные данные пользователя для доступа к API Google от их имени. В следующем фрагменте показано, как составить список файлов в учетной записи Google Диска проверенного пользователя. Обратите внимание на две вещи:

  • Пользователю необходимо не только пройти аутентификацию, но и предоставить вашему приложению область https://www.googleapis.com/auth/drive.readonly , которую вы указываете с помощью атрибута GoogleScopedAuthorize .
  • Мы используем стандартный механизм внедрения зависимостей ASP.NET Core 3 для получения IGoogleAuthProvider , который мы используем для получения учетных данных пользователя.

Код:

  • Сначала добавьте следующие директивы using в ваш контроллер.
    using Google.Apis.Auth.AspNetCore3; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services;       
  • Добавьте действие контроллера следующим образом (и сопроводите его представлением, которое получает модель 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); }       

И это основы. Вы можете взглянуть на HomeController.cs из проекта Google.Apis.Auth.AspNetCore3.IntegrationTests, чтобы узнать, как можно добиться:

  • Только аутентификация пользователя, без каких-либо конкретных областей.
  • Выход пользователя из системы
  • Инкрементальная авторизация по коду. Обратите внимание, что в примере показана добавочная авторизация с атрибутами.
  • Изучите предоставленные области действия
  • Проверка доступа и обновление токенов
  • Принудительно обновить токен доступа. Обратите внимание, что вам не нужно делать это самостоятельно, поскольку Google.Apis.Auth.AspNetCore3 определит, истек ли срок действия токена доступа или близок к нему, и автоматически обновит его.

Сервисный аккаунт

API Google также поддерживают учетные записи служб . В отличие от сценария, в котором клиентское приложение запрашивает доступ к данным конечного пользователя, учетные записи служб предоставляют доступ к собственным данным клиентского приложения.

Ваше клиентское приложение подписывает запрос токена доступа с помощью закрытого ключа, загруженного из консоли Google API . После создания нового идентификатора клиента вам следует выбрать тип приложения «Учетная запись службы», а затем загрузить закрытый ключ. Взгляните на пример нашей сервисной учетной записи с использованием 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();         }     } }

В этом примере создается ServiceAccountCredential . Требуемые области установлены, и происходит вызов FromCertificate , который загружает закрытый ключ из данного X509Certificate2 . Как и во всех других примерах кода, учетные данные задаются как HttpClientInitializer .