Byłem zaangażowany w tworzenie aplikacji do użytku wewnętrznego, za pośrednictwem której użytkownicy mogą przesyłać pliki, które mają być przechowywane na Dysku Google. Ponieważ zaleca się, aby nie używać kont usług jako właścicieli plików, chciałem, aby aplikacja została przesłana w imieniu wyznaczonego konta użytkownika, do którego ma dostęp sysadmin firmy.Niepowodzenie delegowania dostępu do konta Google na konto usługi
Utworzyłem aplikację wraz z kontem usługi. Istnieją dwa klucze utworzone dla konta usługi, jak próbowałem zarówno JSON i formaty pkcs12 próbuje to osiągnąć:
Pobrałem klienta OAuth 2.0 dane identyfikacyjne, a także mają .json i pliki .p12 do kluczy konta usługi (w tej kolejności jak wyżej): wyświetlane
miałem sysadmin przejść przez kolejne etapy wyszczególnionych tutaj, aby delegować uprawnienia do napędu API dostępu do konta usługi: https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account
Wykryliśmy, że jedyną rzeczą, która działała dla "Nazwy klienta" w kroku 4, był "Identyfikator klienta" wymieniony dla aplikacji internetowej (kończący się .apps.googleusercontent.com). Długie identyfikatory szesnastkowym wymienione na klawiszach konto usługi nie były co to wymagane (patrz poniżej):
Wcześniej z powyższym, miałem kod, który będzie utworzyć instancję DriveService który mógłby przesłać bezpośrednio do serwisu konto, odwołuje się do pliku .json dla kluczy konta usługę:
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;
}
który działa na wystawianie i przesyłanie, choć oczywiście nie ma interfejs wWW za dostęp do plików, a wydaje się, że nie radzi sobie takie rzeczy jak metadane uprawnień lub generowanie miniatur dla np Pliki PDF. Dlatego próbuję użyć standardowego konta do przesłanych plików.
Gdy delegacja została najwyraźniej posortowana, spróbowałem dostosować kod przedstawiony w odsyłaczu do delegowania, do którego dołączyłem, łącząc się z kodem pochodzącym z innych krajów w celu wyodrębnienia niezbędnych informacji z pliku klucza .json. Z tego kodu, jak tylko próbuję wykonać dowolne polecenie API, nawet tak proste, jak:
FileList fileList = service.FileList().Execute();
otrzymuję błąd:
wyjątków Szczegóły: Google.Apis.Auth.OAuth2.Responses.TokenResponseException : błąd: "unauthorized_client" Opis: "Nieuprawnione klient lub zakres we wniosku.", Uri: ""
Kod dla tego wysiłku jest:
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;
}
Wreszcie, stworzyłem drugi se klucz konta rvice, aby zapisać.plik P12 w celu lepszego dopasowania do kodu w dokumentacji Przekazanie władzy, ale co skutkuje tym samym wyjątek:
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 istotne klasa gdzie metoda ta mieszka jest:
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();
}
}
I to używane w ten sposób:
var service = new GoogleDrive();
FilesResource.ListRequest listRequest = service.FileList();
FileList fileList = listRequest.Execute();
W tym ostatnim wierszu występuje wyjątek.
Nie rozumiem, dlaczego moje konto usługi nie może działać w imieniu wyznaczonego użytkownika, który jest częścią domeny, dla której konto usługi aplikacji powinno mieć delegowane uprawnienia. Czego tu nie rozumiem?
Może to być spowodowane błędem konfiguracji. Czy wprowadziłeś identyfikator klienta konta usługi w nazwie klienta? Jest to krok nr 5 w [Pełnomocnik dla całej domeny do konta usługi] (https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account) – noogui
@noogui Plik .json wygenerowany dla Klucz konta usługi zawiera wpis "id_klienta", który jest 21 cyfrową liczbą dziesiętną. Użycie go w kroku 5 pokazuje komunikat o błędzie: "Ta nazwa klienta nie została jeszcze zarejestrowana w Google." –