В этом документе описывается протокол OAuth 2.0, случаи его использования, способы получения идентификаторов клиентов и его применение с клиентской библиотекой API Google для .NET.
Протокол OAuth 2.0
OAuth 2.0 – это протокол авторизации, используемый API Google. Рекомендуем ознакомиться с протоколом, перейдя по следующим ссылкам:
Получите идентификаторы клиентов и секретные коды
Идентификаторы клиентов и секретные коды можно получить в Google API Console. Существуют разные типы идентификаторов клиентов, поэтому убедитесь, что вы получили правильный тип для своего приложения:
- Идентификаторы клиентов веб-приложений
- Идентификаторы клиентов установленных приложений
- Идентификаторы клиентов сервисного аккаунта.
Для каждого из приведенных фрагментов кода (кроме фрагмента для сервисного аккаунта) необходимо скачать секретный код клиента и сохранить его в проекте как client_secrets.json.
Учетные данные
Учетные данные пользователя
UserCredential – это потокобезопасный вспомогательный класс, который позволяет использовать токен доступа для работы с защищенными ресурсами.
Обычно срок действия токена доступа истекает через час, после чего при попытке его использовать вы получите сообщение об ошибке.
UserCredential и AuthorizationCodeFlow автоматически обновляют токен, то есть получают новый токен доступа.
Для этого используется долгосрочный токен обновления, который вы получаете вместе с токеном доступа, если используете параметр access_type=offline во время обработки кода авторизации.
В большинстве приложений рекомендуется хранить токен доступа и токен обновления в постоянном хранилище. В противном случае вам придется каждый час показывать конечному пользователю страницу авторизации в браузере, поскольку срок действия токена доступа истекает через час после его получения.
Чтобы обеспечить сохранение токенов доступа и обновления, вы можете предоставить собственную реализацию IDataStore или использовать одну из следующих реализаций, предоставляемых библиотекой:
-
FileDataStoreдля .NET обеспечивает сохранение учетных данных в файле.
ServiceAccountCredential
ServiceAccountCredential
похож на UserCredential, но служит другой цели.
Google OAuth 2.0 поддерживает межсерверное взаимодействие, например между веб-приложением и Google Cloud Storage.
Приложение, отправляющее запрос, должно подтвердить свою личность, чтобы получить доступ к 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 для веб-серверных приложений.
Для большинства сценариев OAuth 2.0 на основе Google в приложениях ASP.NET Core 3 рекомендуется использовать библиотеку
Google.Apis.Auth.AspNetCore3. Он реализует обработчик аутентификации OpenIdConnect, предназначенный для Google. Она поддерживает пошаговую аутентификацию и определяет внедряемый IGoogleAuthProvider для предоставления учетных данных Google, которые можно использовать с Google API.
В этом разделе описывается, как настроить и использовать Google.Apis.Auth.AspNetCore3. Приведенный здесь код основан на Google.Apis.Auth.AspNetCore3.IntegrationTests – полностью рабочем стандартном приложении ASP.NET Core 3.
Если вы хотите использовать эту документацию в качестве руководства, вам понадобится собственное приложение ASP.NET Core 3. Также вам нужно будет выполнить описанные ниже действия.
Требования
- Установите пакет Google.Apis.Auth.AspNetCore3.
- Мы используем Google Drive API, поэтому вам также потребуется установить пакет Google.Apis.Drive.v3.
- Создайте проект Google Cloud, если у вас его ещё нет. инструкциям. Это будет проект, с которым связано ваше приложение.
- Убедитесь, что Google Drive API включен. Чтобы включить 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.
-
Добавьте в файл
Startup.csследующую директиву using.using Google.Apis.Auth.AspNetCore3;
-
В метод
Startup.ConfigureServicesдобавьте следующий код, заменив плейсхолдеры идентификатора клиента и секретного кода клиента значениями из файлаclient_secrets.json. Вы можете загрузить эти значения непосредственно из файла JSON или сохранить их любым другим безопасным способом. Пример загрузки этих значений непосредственно из файла JSON можно найти в методеClientInfo.Loadпроекта Google.Apis.Auth.AspNetCore3.IntegrationTests.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 Console. После создания нового идентификатора клиента выберите тип приложения "Аккаунт сервиса", а затем скачайте закрытый ключ. Ознакомьтесь с примером сервисного аккаунта, использующего 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.