В этом документе описывается OAuth 2.0, когда его использовать, как получать идентификаторы клиентов и как использовать его с клиентской библиотекой Google API для .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
.