18

Zuerst möchte ich erklären, was ich versuche, da dies eine zweiteilige Frage ist."Anmeldung erforderlich" 401 Unautorisierte Nachricht beim Aufruf der Google Kalender-API der v3 mit einem Dienstkonto über OAuth 2.0

Ich erstelle einen JAX-RS-Dienst, der sich intern mit einem Google-Konto über OAuth2 authentifiziert, damit er auf einen Google-Kalender zugreifen und ihn bearbeiten kann. Dieser Dienst wird von einer Website (Joomla) aufgerufen, die es Benutzern, die sich auf der Website anmelden, ermöglicht, ihre E-Mail-Adresse bei Kalenderereignissen zu registrieren, damit sie E-Mail-Benachrichtigungen erhalten, wenn die Ereignisse in der Nähe sind. Diese Nutzer kennen das zugrunde liegende Google-Konto nicht.

Also meine erste Frage, ist Service Account Authentifizierung die richtige Sache? Betrachtet man die Google-Dokumente, ist dies der einzige Anwendungsfall, der eine nicht-menschliche Authentifizierung ermöglicht (also Server-zu-Server-Authentifizierung).

Das zweite Problem ist, dass ich Code geschrieben habe, um dies zu tun, aber ich bekomme eine 401/nicht autorisierte Antwort zurück den folgenden Fehler zurück, wenn ich die execute-Methode den Kalender-Feed aufrufen. Dieser Code wurde aus den Google-Beispielen entfernt.

Ich verwende v3-rev3-1.5.0-beta der Google Kalender-API. Ich habe die Kalender-API im Konto aktiviert und einen privaten Schlüssel erstellt und heruntergeladen, der im folgenden Code verwendet wird.

Ich rufe den Code unten in Eclipse lokal, nicht von einem Webserver.

So ist der erste Anruf, den ich machen, ist ein Credential-Objekt zurück (Id der mit X verschleierten):

private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); 
private static final JsonFactory JSON_FACTORY = new JacksonFactory(); 
. 
. 
. 
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT) 
      .setJsonFactory(JSON_FACTORY) 
      .setServiceAccountId("[email protected]") 
      .setServiceAccountScopes(CalendarScopes.CALENDAR) 
      .setServiceAccountPrivateKeyFromP12File(new File("D:/3cd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd635e-privatekey.p12")) 
      .build(); 

Der nächste Schritt ist, um dann die Kalender-API aufrufen, wie so (kein anderer Code genannt in between):

Calendar calendar = Calendar.builder(HTTP_TRANSPORT, JSON_FACTORY) 
     .setApplicationName("TestApp-Calendar/1.0").setHttpRequestInitializer(credential) 
     .build(); 

CalendarList feed = calendar.calendarList().list().execute(); 

der Aufruf() zur Liste execute() ergibt folgende Fehler:.

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized { "code" : 401, "errors" : [ { "domain" : "global", "location" : "Authorization", "locationType" : "header", "message" : "Login Required", "reason" : "required" } ], "message" : "Login Required" } at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:159) at com.google.api.client.googleapis.json.GoogleJsonResponseException.execute(GoogleJsonResponseException.java:187) at com.google.api.client.googleapis.services.GoogleClient.executeUnparsed(GoogleClient.java:115) at com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:112) at com.google.api.services.calendar.Calendar$CalendarList$List.execute(Calendar.java:510) at uk.org.reigatepriorybowmen.Service.registerEmailForAllCalendarEvents(Service.java:55) at uk.org.reigatepriorybowmen.Service.main(Service.java:74)

Das Dienstkonto ist wie folgt aufgebaut:

enter image description here

Also, was mache ich falsch ?! Ich habe Stunden damit verbracht, nach Lösungen zu suchen. Das ist meine letzte Hoffnung.

Vielen Dank im Voraus für Ihre Hilfe.

Justin

+1

haben Sie jemals die Lösung dafür gefunden? –

Antwort

1

Ich glaube, Sie müssen den Benutzer angeben, die Sie ausgeben möchten.

Die Art und Weise, wie Sie ServiceAccount gerade verwenden, gilt nur für den Zugriff auf Daten, die sich auf Ihre Anwendung oder Ihr Dienstkonto beziehen. Da Sie auf Google Kalender-Daten zugreifen möchten, müssen Sie ein Google Apps-Domain-Administrator mit Zugriffsrechten für die Daten Ihrer Domain-Nutzer sein. Lassen Sie mich wissen, wenn ich nicht korrekt bin. Google Kalender-Daten gehören den Benutzern. Sie müssen also angeben, welchen Benutzer Sie imitieren möchten.

dies mit Java zu tun, es scheint, dass Sie Gebrauch GoogleCredential.Builder#setServiceAccountUser(String)

Bitte versuchen Sie es tun müssen:

GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT) 
     .setJsonFactory(JSON_FACTORY) 
     .setServiceAccountId("[email protected]") 
     .setServiceAccountScopes(CalendarScopes.CALENDAR) 
     .setServiceAccountPrivateKeyFromP12File(new File("/path/to/privatekey.p12")) 
     .setServiceAccountUser("[email protected]") 
     .build(); 

Auch, wenn Sie einen Service Account Schlüssel in Ihrem API-Projekt erstellt haben (von der APIs Konsole), müssen Sie dieses Projekt zur Liste der autorisierten Drittanbieter-App im cPanel hinzufügen. Weitere Informationen hierzu finden Sie unter here. Die "Client-ID", die Sie verwenden müssen, ist diejenige, die an den Dienstkonto-Schlüssel gebunden ist und wie folgt aussieht: <APP_ID>-<OTHER_KEY>.apps.googleusercontent.com

+0

Hallo, danke, ich werde es einen Wirbel geben und Posten zurück, wenn es funktioniert. Ich habe das Projekt seither aufgegeben, aber ich würde immer noch gerne wissen, wie ich das zum Nachschlagen funktioniere. –

+0

OK Ich habe versucht, die Methode setServiceAccountUser() aufzurufen und erhalte den gleichen Fehler. Ich kann nicht glauben, dass Google dies so schwierig gemacht hat! –

+0

Sie müssen auch die Client-ID in Ihrer Domäne aufheben, s cPanel. Ich habe hinzugefügt, wie das in meiner Antwort funktioniert. Ich stimme zu, dass 2-Legged OAuth 1 meiner Meinung nach etwas einfacher ist. HOpe wir können etwas einfacher als das mit OAuth 2.0 eines Tages bekommen ... – Nivco

1

Ein solches Verhalten kann auftreten, wenn Sie keinen api-Benutzer im Admin-Bereich hinzugefügt haben (in Ihrem Fall ist das Dokumenten-Panel wahrscheinlich), Zum Beispiel müssen Sie in Google Analytics neue Benutzer hinzufügen, deren E-Mail-Adresse dieselbe ist, die Sie von API erhalten haben (wird vom Google API-Dienstkonto nach dem Erstellen des privaten Schlüssels bereitgestellt). In der Analytik sieht es wie folgt aus:

example in google analytics

+0

Hallo, danke, ich werde es einen Wirbel geben und Posten zurück, wenn es funktioniert. Ich habe das Projekt seither aufgegeben, aber ich würde immer noch gerne wissen, wie ich das zum Nachschlagen funktioniere. –

+0

Ich kann nicht sehen, wo die Benutzer in der API-Konsole festgelegt sind. –

+0

Es ist keine API-Konsole, es ist in Google Analytics Panel. Hier ist eine einfache Anleitung versuchen Sie es: [Link] (http://www.pimcore.org/wiki/display/PIMCORE/Setup+Google+Analytics+Reporting+mit+OAuth2+Service+Accounts+ (seit + 1.4.6)) –

5

Wie für die 401, es scheint eine gewisse Kuriosität mit den Google-API. Ich finde das erste Mal, dass ich meine App in einer Weile laufen, und dann in scheinbar zufälligen Abständen Stunden auseinander, ich bekomme immer eine 401. In der zweiten oder dritten Runde loggt es sich tatsächlich.

Das Verhalten ist sogar berücksichtigt in der Google-Task-API Beispielcode here.

Hinweis Dieser Code:

void onRequestCompleted() { 
received401 = false; 
} 

void handleGoogleException(IOException e) { 
if (e instanceof GoogleJsonResponseException) { 
    GoogleJsonResponseException exception = (GoogleJsonResponseException) e; 
    if (exception.getStatusCode() == 401 && !received401) { 
    received401 = true; 
    accountManager.invalidateAuthToken(credential.getAccessToken()); 
    credential.setAccessToken(null); 
    SharedPreferences.Editor editor2 = settings.edit(); 
    editor2.remove(PREF_AUTH_TOKEN); 
    editor2.commit(); 
    gotAccount(); 
    return; 
    } 
} 
Log.e(TAG, e.getMessage(), e); 

}

In Googles eigenen Codebeispiel sie 401. Bestimmung zum ersten Mal gemacht haben Es könnte einige besondere Sicherheitsproblem werden, die im Code behandelt werden muss.

0

OK, also habe ich mit diesem gespielt und habe den 401-Fehler hinter mir, aber jetzt treffe ich einen 403. Allerdings werde ich den Code, den ich geschrieben habe, zumindest dem 401-Problem beantworten.

Ich habe keine der Service-Kontoeinstellungen geändert oder einen der Schlüssel usw. neu generiert, das ist egal.

Was hat sich geändert, ist etwas von dem Code, und ich habe auf v3r20lv1.12.0-beta der Kalender-API aktualisiert.

Der folgende Code, wie im OP oben beschrieben, bleibt gleich, das heißt:

private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); 
private static final JsonFactory JSON_FACTORY = new JacksonFactory(); 
. 
. 
. 
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT) 
     .setJsonFactory(JSON_FACTORY) 
     .setServiceAccountId("[email protected]") 
     .setServiceAccountScopes(CalendarScopes.CALENDAR) 
     .setServiceAccountPrivateKeyFromP12File(new File("D:/3cd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd635e-privatekey.p12")) 
     .build(); 

Der Code einen Griff für den Kalender erhalten hat sich verändert, aber diese durch eine API-Änderung gezwungen wurde:

Calendar calendar = new Calendar(HTTP_TRANSPORT, JSON_FACTORY, credential); 

An dieser Stelle kann ich durch meinen Kalender laufen und die Ereignisse sehen, die durch den folgenden Code ausgeführt wird (dies druckt ein Ereignis Zusammenfassung):

Events events = calendar.events().list(CALENDAR_ID).execute(); 

for (Event event : events.getItems()) 
{ 
    System.out.println(event.getSummary()); 
} 

Aber, wenn ich versuche, ein Ereignis zu aktualisieren, erhalte ich einen Fehler 403 Verboten. Ich werde dafür einen eigenen Thread anlegen und die beiden Threads miteinander verbinden.

Vielen Dank an alle für Ihre Hilfe!

EDIT: here ist der neue Thread.

1

Ich bin ein Android Mobile App Entwickler. Ich erstelle eine Bewerbung mit der Google Kalender-API (OAuth 2.0). Ich habe auch diesen Fehler gemacht. Aber jetzt habe ich den Fehler behoben. Ich schreibe das Szenario und die Lösung dafür.
die URL des Kalenderereignis für den bestimmten Kalender (Mobile App API) bekommen:

https://www.googleapis.com/calendar/v3/calendars/en.indian%23holiday%40group.v.calendar.google.com/events?access_token=ya29.AHES6ZQyP3iDZM8PF-7ZqZE8oKmWAgUX55sPGPTjGbM5A 

In dieser URL müssen wir die calendarId hinzufügen. Das Format der URL ist;

https://www.googleapis.com/calendar/v3/calendars/<calendarId>/events 

Ich habe die calendarId vor dem Hinzufügen zur URL nicht codiert. Ich habe die calendarId codiert und dann die HTTP-Anfrage gemacht. Alles ging dann gut.

final String accessToken=dataStore.getAccessToken(); 

    List<NameValuePair> params = new LinkedList<NameValuePair>(); 
    params.add(new BasicNameValuePair("access_token", accessToken)); 
    String paramString = URLEncodedUtils.format(params, "utf-8"); 

    final String url = String.format(AuthConstants.CALENDAR_EVENTS_URI,URLEncoder.encode(calendarId))+"?"+ paramString; 

Jetzt werden die Kalenderereignisse im JSON zurückgegeben.

0

Haben Sie die Berechtigung für die richtigen Bereiche angefordert? Sie sollten immer https://www.googleapis.com/auth/userinfo.profile

Verwandte Themen