В этом документе описывается 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 .