2016-11-28 27 views
13

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ąć:

API Manager Credentials page

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

Downloaded files for client and service accounts

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):

Authorized API client access

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?

+0

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

+0

@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." –

Odpowiedz

6

Znalazłem odpowiedź sam, i to było konfiguracją, a nie kodem. Łącze, które udostępniłem z krokami delegowania uprawnień, nie wspomina o opcji dostępnej po utworzeniu konta usługi: pole wyboru, które mówi, że konto będzie kwalifikować się do delegowania na całą domenę (DwD).

Ten link opisuje stworzenie konta usługi i delegacji trafniej: https://developers.google.com/identity/protocols/OAuth2ServiceAccount

ja nie wiedziałem o DWD kiedy stworzył konto usługi, a więc nie wybrał tę opcję. Można wrócić i edytować konto usługi, aby je wybrać. Kiedy to zrobiłem, udało mi się pobrać prawidłowy identyfikator klienta do użycia w części "Zarządzaj dostępem klienta API" konsoli administracyjnej. Korzystanie z metody GetServiceC() działa zgodnie z zamierzeniami i mogę pobierać pliki dla użytkowników w tej samej domenie Aplikacji.

Jest to pole, które musi być zaznaczone dla konta usługi, aby kwalifikować się do całej domeny upoważnień:

Creation of a new service account - DwD checkbox

ta jest dostępna dodatkowa informacja raz to zrobisz (wyrzucenie z konta usługi obok że nie nie mają pole zaznaczone, dla porównania):

Comparison of service accounts with and without DwD

+0

Nie widziałem opcji delegowania nowej domeny w interfejsie genów kluczowych i nigdy jej nie potrzebowałem - to musi być nowym atrybutem. Cieszę się, że rozwiązałeś problem! –

-2

Większość wszystko wygląda ok, ale:

kod

A. Zastosowanie ServiceC, nie wiem, czy sprawy przedmiot typowania ale linia:

var credential = new ServiceAccountCredential... 

powinny być

ServiceAccountCredential credential = new ServiceAccountCredential... 

B. Sprawdź że plik P12 w ServiceC to prawdziwy plik P12, który faktycznie przesłałeś do swojego środowiska, w którym to uruchamiasz.

C. zaktualizuj swoje pytanie za pomocą kodu, który jest dokładnie używany do utworzenia i wywołania usługi: filelist: execute code. W ten sposób jest więcej jasności i mniej założeń.

+0

A. Używanie 'var' nie robi różnicy, zobacz https://msdn.microsoft.com/en-us/library/bb384061.aspx –

+0

(B) Używam go na moim komputerze lokalnym; Wyjaśniłem kod, aby pokazać, że ładuję go bezpośrednio z folderu App_Data. (C) Dodałem rzeczywisty kod do wykonania polecenia FileList (wspólne dla wszystkich metod GetService()). –

1

Możesz zaznaczyć pole wyboru Włączanie delegacji G Suite na domenę, gdy tworzysz konto usługi w panelu administracyjnym.

Pozdrowienia

+0

Dzięki, ale jak widać, już udało mi się odkryć, gdzie się pomyliłem! :) –