Я занимаюсь созданием внутреннего приложения, через которое пользователи могут загружать файлы, которые будут храниться на Google Диске. Поскольку рекомендуется не использовать учетные записи служб в качестве владельцев файлов, я хотел, чтобы приложение загружалось от имени назначенной учетной записи пользователя, к которой имеет доступ sysadmin компании.
Я создал приложение вместе с учетной записью службы. Для учетной записи службы есть два ключа, поскольку я попытался использовать форматы JSON и PKCS12, пытаясь добиться этого:
Я загрузил данные идентификатора клиента OAuth 2.0, а также файлы .json и .p12 для ключей учетной записи службы (в указанном выше порядке):
У меня был мой системный администратор, пройдя шаги, подробно описанные здесь, чтобы делегировать полномочия для доступа к API-интерфейсу API для учетной записи службы: https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account p >
Мы обнаружили, что единственное, что работало для "имени клиента" на шаге 4, - это "Идентификатор клиента", указанный для веб-приложения (завершение .apps.googleusercontent.com). Длинные шестнадцатеричные идентификаторы, перечисленные для ключей учетной записи службы, не соответствуют требованиям (см. Ниже):
Раньше к вышесказанному у меня был код, который создавал бы экземпляр 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", Описание: "Неавторизованный клиент или область в запросе". Uri: ""
Код для этого усилия:
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;
}
Наконец, я создал второй ключ учетной записи службы, чтобы сохранить файл .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;
}
Минимальный соответствующий класс, в котором живет этот метод:
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();
Исключение происходит в этой последней строке.
Я не понимаю, почему моя учетная запись службы не может действовать от имени назначенного пользователя, который является частью домена, для которого учетная запись службы приложений должна иметь делегированные полномочия. Что я здесь неправильно понял?