it-swarm.com.de

"Login erforderlich" 401 Unberechtigte Nachricht, wenn Sie die v3-Google-Kalender-API mit einem Dienstkonto über OAuth 2.0 aufrufen

Lassen Sie mich zunächst erklären, was ich versuche, da dies eine zweiteilige Frage ist.

Ich baue einen JAX-RS-Dienst auf, der sich intern mit einem Google-Konto über OAuth2 authentifiziert, sodass er auf einen Google-Kalender zugreifen und diesen bearbeiten kann. Dieser Dienst wird von einer Website (Joomla) aufgerufen, auf der sich Benutzer, die sich auf der Website anmelden, registrieren, um ihre E-Mail-Adresse mit Kalenderereignissen zu registrieren, um E-Mail-Benachrichtigungen zu erhalten, wenn die Ereignisse in der Nähe sind. Diese Nutzer haben keine Kenntnis vom zugrunde liegenden Google-Konto.

Also ist meine erste Frage die richtige Verwendung der Service Account Authentifizierung? Wenn Sie sich die Google-Dokumente ansehen, ist dies der einzige Anwendungsfall, der für die nicht-menschliche Authentifizierung (also Server-zu-Server-Authentifizierung) sorgt.

Das zweite Problem ist, dass ich etwas Code geschrieben habe, um dies zu tun, aber ich erhalte den folgenden Fehler zurück, wenn ich die Ausführungsmethode den Kalender-Feed nenne. 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 in Eclipse lokal auf, nicht von einem Webserver.

Der erste Aufruf, den ich mache, besteht darin, ein Objekt mit Anmeldeinformationen zurückzuholen (die IDs werden durch X verschleiert):

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 dann das Aufrufen der Kalender-API wie auch immer (kein anderer Code wird dazwischen aufgerufen):

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

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

Der Aufruf von list (). Execute () führt zu dem folgenden Fehler:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unberechtigt { "Code": 401, "Fehler": [{ "Domäne": "global", "location": "Authorization", "locationType": "header", "message": "Login erforderlich", "Grund": "Erforderlich" }], "message": "Login erforderlich" } unter com.google.api.client.googleapis.json.GoogleJsonResponseException.from (GoogleJsonResponseException.Java:159) unter com.google.api.client.googleapis.json.GoogleJsonResponseException.execute (GoogleJsonResponseException.Java:187) unter com.google.api.client.googleapis.services.GoogleClient.executeUnparsed (GoogleClient.Java:115) unter com.google.api.client.http.json.JsonHttpRequest.executeUnparsed (JsonHttpRequest.Java:112) unter com.google.api.services.calendar.Calendar $ CalendarList $ List.execute (Calendar.Java:510) at uk.org.reigatepriorybowmen.Service.registerEmailForAllCalendarEvents (Service.Java:55) bei uk.org.reigatepriorybowmen.Service.main (Service.Java:74)

Das Dienstkonto wird wie folgt eingerichtet:

enter image description here

Also, was mache ich falsch ?! Ich habe stundenlang gegoogelt und nach Lösungen gesucht, dies ist meine letzte Hoffnung.

Vielen Dank im Voraus für Ihre Hilfe.

Justin

18
Justin Phillips

Was die 401 angeht, so scheint es mit der API von Google etwas seltsam zu sein. Ich finde, wenn ich meine App zum ersten Mal in Betrieb nehme, und dann in scheinbar zufälligen Stunden verteilt, bekomme ich immer eine 401. In der zweiten oder dritten Runde meldet sie sich tatsächlich an.

Das Verhalten wird sogar im Task-API-Beispielcode von Google hier berücksichtigt.

Beachten Sie diesen 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 eigenem Codebeispiel wurde erstmals eine Vorkehrung getroffen 401. Es könnte ein besonderes Sicherheitsproblem sein, das mit Code behandelt werden muss.

Ich denke, Sie müssen den Benutzer angeben, den Sie imitieren möchten.

Die Art und Weise, wie Sie ServiceAccount jetzt verwenden, gilt nur für den Zugriff auf Daten, die sich auf Ihre Anwendung oder Ihr Dienstkonto selbst beziehen. Da Sie auf Google Kalender-Daten zugreifen möchten, müssen Sie ein Google Apps-Domänenadministrator sein, der über Berechtigungen zum Zugriff auf die Daten Ihrer Domänenbenutzer verfügt. Lassen Sie mich wissen, wenn ich nicht korrekt bin. Google Kalender-Daten gehören zu den Nutzern. Sie müssen also angeben, welcher Benutzer Sie imitieren möchten.

Um dies mit Java zu tun, müssen Sie GoogleCredential.Builder # setServiceAccountUser (String) verwenden.

Bitte versuche:

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();

Nachdem Sie in Ihrem API-Projekt (über die APIs Console) einen Service Account-Schlüssel erstellt haben, müssen Sie dieses Projekt der Liste der autorisierten Drittanbieter-Apps im cPanel hinzufügen. Mehr Informationen dazu finden Sie hier . Die "Client-ID", die Sie verwenden müssen, ist diejenige, die an den Service Account-Schlüssel gebunden ist, und sieht wie <APP_ID>-<OTHER_KEY>.apps.googleusercontent.com aus.

1
Nicolas Garnier

Ich bin ein Android Mobile App-Entwickler. Ich mache eine Anwendung mit der Google Kalender-API (OAuth 2.0). Ich habe auch den gleichen Fehler erlebt. Aber jetzt habe ich den Fehler behoben. Ich schreibe das Szenario und die Lösung dafür.
.__ Die URL des Abrufs des Kalenderereignisses für den jeweiligen Kalender (Mobile App API):

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 verschlüsselt und dann die Http-Anforderung gestellt. Alles lief 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 in JSON zurückgegeben.

1
Khushboo

Ein solches Verhalten kann auftreten, wenn Sie keinen api-Benutzer im Admin-Panel hinzugefügt haben (in Ihrem Fall das Documents-Panel, denke ich). In Google Analytics müssen Sie zum Beispiel einen neuen Benutzer hinzufügen, dessen E-Mail-Adresse derselbe ist, wie Sie ihn von api erhalten haben (bereitgestellt von der Google API-Dienstkonto nach dem Erstellen des privaten Schlüssels) ..__ In der Analyse sieht es folgendermaßen aus:

example in google analytics

1
Dawid D

Haben Sie um Erlaubnis für die richtigen Bereiche gebeten? Sie sollten immer https://www.googleapis.com/auth/userinfo.profile angeben.

0
Kees de Kooter

OK, also habe ich damit rumgespielt und habe den 401-Fehler überwunden, aber jetzt treffe ich eine 403. Allerdings werde ich den Code detailliert beschreiben, den ich geschrieben habe, der zumindest das 401-Problem löst.

Ich habe keine der Dienstkontoeinstellungen geändert oder einen der Schlüssel usw. nicht neu generiert. Das ist alles das Gleiche.

Was sich geändert hat, ist ein Teil des Codes, und ich habe ein Upgrade auf v3r20lv1.12.0-beta der Kalender-API durchgeführt.

Der Code unten, wie oben im OP beschrieben, bleibt derselbe, d. H .:

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 zum Abrufen eines Handles für den Kalender wurde geändert. Dies wurde jedoch durch eine API-Änderung erzwungen:

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

An diesem Punkt kann ich meinen Kalender durchlaufen und die Ereignisse sehen, indem ich den folgenden Code ausführt (dies gibt eine Ereignisübersicht aus):

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

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

Wenn ich jedoch versuche, ein Ereignis zu aktualisieren, wird der Fehler 403 Forbidden angezeigt. Ich werde dafür einen separaten Thread aufbringen und die beiden Threads miteinander verbinden.

Vielen Dank an alle für Ihre Hilfe!

EDIT: hier ist der neue Thread.

0
Justin Phillips