2016-11-28 2 views
13

Я занимаюсь созданием внутреннего приложения, через которое пользователи могут загружать файлы, которые будут храниться на Google Диске. Поскольку рекомендуется не использовать учетные записи служб в качестве владельцев файлов, я хотел, чтобы приложение загружалось от имени назначенной учетной записи пользователя, к которой имеет доступ sysadmin компании.Неспособность делегировать доступ Google Диска к учетной записи службы

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

API Manager Credentials page

Я скачал OAuth 2.0 клиент детали ID, а также имею .json и файлы .p12 для ключей учетной записи службы (в том порядке, как показано выше):

Downloaded files for client and service accounts

Я был мой сисадмин пройти шаги подробно здесь, чтобы делегировать полномочия для доступа к API Диска к учетной записи службы: https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account

Мы обнаружили, что единственное, что работало для «имени клиента» на шаге 4, - это «Идентификатор клиента», указанный для веб-приложения (завершение .apps.googleusercontent.com). Длинные шестнадцатеричные идентификаторы, указанные для ключей учетной записи службы не были, что это необходимо (см ниже):

Authorized API client access

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

private DriveService GetServiceA() 
{ 
    var settings = SettingsProvider.GetInstance(); 

    string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json"); 
    var scopes = new string[] { DriveService.Scope.Drive }; 

    var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read); 
    var credential = GoogleCredential.FromStream(stream); 
    credential = credential.CreateScoped(scopes); 

    var service = new DriveService(new BaseClientService.Initializer() 
    { 
     HttpClientInitializer = credential, 
     ApplicationName = "MyAppName" 
    }); 

    return service; 
} 

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

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

FileList fileList = service.FileList().Execute(); 

Я получаю сообщение об ошибке:

Сведения об исключении: Google.Apis.Auth.OAuth2.Responses.TokenResponseException Ошибка: «unauthorized_client», Описание: «Несанкционированное клиент или сфера в запросе.» Ури: «»

код для этой работы является:

private DriveService GetServiceB() 
{ 
    var settings = SettingsProvider.GetInstance(); 

    string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json"); 
    string serviceAccountEmail = "<account-email>@<project-id>.iam.gserviceaccount.com"; 
    var scopes = new string[] { DriveService.Scope.Drive }; 

    var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read); 
    var reader = new IO.StreamReader(stream); 
    string jsonCreds = reader.ReadToEnd(); 
    var o = JObject.Parse(jsonCreds); 
    string privateKey = o["private_key"].ToString(); 

    var credential = new ServiceAccountCredential(
    new ServiceAccountCredential.Initializer(serviceAccountEmail) 
    { 
     Scopes = scopes, 
     User = "[email protected]" 
    } 
    .FromPrivateKey(privateKey) 
); 

    var service = new DriveService(new BaseClientService.Initializer() 
    { 
    HttpClientInitializer = credential, 
    ApplicationName = "MyAppName" 
    }); 

    return service; 
} 

Наконец, я создал второй се rvice для сохранения.p12 файл для того, чтобы более точно соответствовать код в документации делегирования полномочий, но приводит к тем же исключением:

private DriveService GetServiceC() 
{ 
    var settings = SettingsProvider.GetInstance(); 

    string p12KeyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.p12"); 
    string serviceAccountEmail = "<account-email>@<project-id>.iam.gserviceaccount.com"; 
    var scopes = new string[] { DriveService.Scope.Drive }; // Full access 

    X509Certificate2 certificate = new X509Certificate2(
    p12KeyFilePath, 
    "notasecret", 
    X509KeyStorageFlags.Exportable 
); 

    var credential = new ServiceAccountCredential(
    new ServiceAccountCredential.Initializer(serviceAccountEmail) 
    { 
     Scopes = scopes, 
     User = "[email protected]" 
    } 
    .FromCertificate(certificate) 
); 

    var service = new DriveService(new BaseClientService.Initializer() 
    { 
    HttpClientInitializer = credential, 
    ApplicationName = "MyAppName" 
    }); 

    return service; 
} 

minimial соответствующий класс, где этот метод живет является:

public class GoogleDrive 
{ 
    public DriveService Service { get; private set; } 

    public GoogleDrive() 
    { 
    this.Service = this.GetService(); 
    } 

    private DriveService GetService() 
    { 
    // Code from either A, B or C 
    } 

    public FilesResource.ListRequest FileList() 
    { 
    return this.Service.Files.List(); 
    } 
} 

И это используется таким образом:

var service = new GoogleDrive(); 
FilesResource.ListRequest listRequest = service.FileList(); 
FileList fileList = listRequest.Execute(); 

Исключение происходит на этой последней строке.

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

+0

Это может быть вопрос конфигурации ошибки. Вы указали идентификатор клиента учетной записи службы в имени клиента? Это шаг № 5 в домене [Делегировать полномочия домена для вашей учетной записи службы] (https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account) – noogui

+0

@noogui Файл .json, созданный для ключ учетной записи службы содержит запись «client_id», которая является 21-значным десятичным числом. Использование этого для шага № 5 показывает сообщение об ошибке: «Это имя клиента еще не было зарегистрировано в Google». –

ответ

6

Я сам нашел ответ, и это было Конфигурация, а не код. В ссылке, которую я разделял с шагами для делегирования полномочий, не упоминается опция, доступная, когда создает учетную запись службы: флажок, указывающий, что учетная запись будет иметь право на делегирование домена (DwD).

Этой ссылка описывает создание учетной записи службы и делегирование более точно: https://developers.google.com/identity/protocols/OAuth2ServiceAccount

я не знал о DWD, когда я создал учетную запись службы, и поэтому я не выбрал этот вариант. Для его выбора можно вернуться и отредактировать учетную запись службы. Как только я это сделал, мне удалось получить правильный идентификатор клиента для использования в разделе «Управление клиентским доступом к API» в консоли администратора. Используя метод GetServiceC(), он работает по назначению, и я могу получить файлы для пользователей в том же домене Apps.

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

Creation of a new service account - DwD checkbox

Это дополнительная информация, как только вы сделали, что (с холостой учетной записи службы вместе, что сделал не галочкой поле, для сравнения):

Comparison of service accounts with and without DwD

+0

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

-2

Большинство все выглядит нормально, но:

A. Используйте ServiceC код, не уверен, что если вопросы объект типирование, но ваша линия:

var credential = new ServiceAccountCredential... 

должен быть

ServiceAccountCredential credential = new ServiceAccountCredential... 

B. Проверить что файл P12 в ServiceC является реальным файлом P12, который вы фактически загрузили в свою среду, в которой вы работаете.

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

+0

A. Использование 'var' не имеет значения, см. Https://msdn.microsoft.com/en-us/library/bb384061.aspx –

+0

(B) Я запускаю его на своей локальной машине; Я уточнил код, чтобы показать, что я загружаю его непосредственно из папки App_Data. (C) Я добавил фактический код для выполнения команды FileList (общий для всех методов GetService()) –

1

Вы можете пометить галочкой Включить делегирование домена G Suite при создании учетной записи службы на панели администратора.

С уважением

+0

Спасибо, но, как вы видите, мне уже удалось обнаружить, где я ошибся! :) –

Смежные вопросы