Требуется вход в систему 401 с использованием Google ServiceAccountCredential с использованием API-интерфейса администратора Google - PullRequest
0 голосов
/ 02 мая 2018

Я пытался следовать простому примеру, указанному здесь: https://developers.google.com/admin-sdk/directory/v1/quickstart/dotnet

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

Здесь он имеет доступ к органам , что я пытаюсь перечислить в Справочнике API

scopes are assigned

Здесь определена моя учетная запись службы

enter image description here

Вот мои учетные данные

enter image description here

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

Но затем я передаю учетные данные инициализатору службы, и когда я создаю и выполняю запрос, он не работает с

{"Google.Apis.Requests.RequestError\r\nLogin Required [401]\r\nErrors [\r\n\tMessage[Login Required] Location[Authorization - header] Reason[required] Domain[global]\r\n]\r\n"}

Вот код:

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using System;
using System.Collections.Generic;
using System.IO;

namespace DirectoryQuickstart
{
    class Program
    {
        static string[] Scopes = { DirectoryService.Scope.AdminDirectoryUser, DirectoryService.Scope.AdminDirectoryOrgunit };
        static string ApplicationName = "slea-crm";
        static string Secret = "gsuite-secret.json";

        static void Main(string[] args)
        {

            ServiceAccountCredential sac = GoogleCredential.FromFile(Secret).CreateScoped(Scopes).UnderlyingCredential as ServiceAccountCredential;

            var token = sac.GetAccessTokenForRequestAsync().Result;

            // Create Directory API service.
            var service = new DirectoryService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = sac,

                ApplicationName = ApplicationName,
            });

            OrgunitsResource.ListRequest request = service.Orgunits.List(customerId: "REDACTED");
            IList<OrgUnit> orgUnits = request.Execute().OrganizationUnits;

            if (orgUnits != null && orgUnits.Count > 0)
            {
                foreach (var orgUnit in orgUnits)
                {
                    Console.WriteLine("{0} ({1})", orgUnit.Name, orgUnit.OrgUnitPath);
                }
            }
            else
            {
                Console.WriteLine("No orgunits found.");
            }
            Console.Read();

        }
    }
}

Вот содержимое моего секрета JSON (с редакциями)

enter image description here

Что мне здесь не хватает?

РЕДАКТИРОВАТЬ : ОК, я делаю код останова, пока он генерирует запрос, и я вижу, что нигде не указано, как он устанавливает носитель токена авторизации в заголовках. Зачем? Я ожидаю, что этот класс HttpClientInitializer позаботится об этом, поскольку в документации API говорится, что он знает, как с этим справиться, и каждый найденный в Интернете пример показывает, что он просто передает учетные данные в инициализатор службы. Но когда я прошел через это, хотя учетным данным уже был предоставлен токен доступа, и он существует внутри него, нигде в запросе не обновляется заголовок.

Единственное, что я могу видеть, - это какой-то способ добавить перехватчик HTTP-запросов, где, возможно, я мог бы сделать это сам, но вау, это кажется действительно ... странным - после всей этой работы, которую они проделали на клиенте dotnet SDK, я, честно говоря, мог бы просто написать прямо в HTTP API, и было бы намного проще и легче следовать.

enter image description here

1 Ответ

0 голосов
/ 04 мая 2018

Недостающий фрагмент головоломки - это строка:

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .UnderlyingCredential as ServiceAccountCredential;

Необходимо изменить на это:

static string userName = "admin@yourdomain.com" // valid user in your org

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .CreateWithUser(userName)
    .UnderlyingCredential as ServiceAccountCredential;

Java / Python / Go пример того, как сделать подобное здесь: https://developers.google.com/admin-sdk/directory/v1/guides/delegation#create_the_service_account_and_its_credentials

...