18

Innanzitutto, vorrei spiegare cosa sto cercando di fare, poiché si tratta di una domanda in due parti."Accesso richiesto" 401 Messaggio non autorizzato quando si chiama l'API di Google Calendar v3 utilizzando un account di servizio tramite OAuth 2.0

Sto costruendo un servizio JAX-RS che si autentica internamente con un account Google tramite OAuth2, quindi può accedere e manipolare un calendario di Google. Questo servizio verrà chiamato da un sito Web (Joomla), che consentirà agli utenti che accedono al sito di registrare il proprio indirizzo email con gli eventi del calendario in modo che possano ricevere notifiche via email quando gli eventi sono vicini. Questi utenti non sono a conoscenza dell'account Google sottostante.

Quindi la mia prima domanda, sta usando l'autenticazione dell'account di servizio la cosa giusta? Guardando i documenti di Google, è l'unico caso d'uso che si rivolge all'autenticazione non umana (quindi all'autenticazione da server a server).

Il secondo problema è che ho scritto del codice per fare questo, ma torno indietro 401/La risposta non autorizzata indietro il seguente errore quando chiamo il metodo di esecuzione il feed del calendario. Questo codice è stato rimosso dagli esempi di Google.

Sto utilizzando v3-rev3-1.5.0-beta dell'API di Google Calendar. Ho attivato l'API Calendar nell'account e creato e scaricato una chiave privata, utilizzata nel codice seguente.

Sto chiamando il codice qui sotto in Eclipse localmente, non da un server web.

Quindi la prima chiamata che faccio è quello di tornare un oggetto credenziale (di Id offuscato con X di):

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

Il passo successivo è quello di poi chiamare l'API calendario, in questo modo (nessun altro codice chiamato in tra):

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

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

la chiamata di elencare() execute() genera il seguente errore:.

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)

L'account di servizio è configurato come segue:

enter image description here

Allora, che cosa faccio di sbagliato ?! Ho passato ore a cercare su Google in cerca di soluzioni, quindi questa è la mia ultima speranza.

Molte grazie in anticipo per il vostro aiuto.

Justin

+1

hai mai trovato la soluzione a questo? –

risposta

1

Penso che sarà necessario specificare l'utente che si sta tentando di impersonare.

Il modo in cui si utilizza ServiceAccount in questo momento è valido solo per accedere ai dati relativi alla propria applicazione o al proprio account di servizio stesso. Dal momento che desideri accedere ai dati di Google Calendar devi essere un amministratore di dominio di Google Apps con privilegi per accedere a qualsiasi dato dell'utente del tuo dominio - fammi sapere se non sono corretto. I dati di Google Calendar appartengono agli utenti, quindi è necessario specificare quale utente si sta tentando di impersonare.

di farlo usando Java, sembra che avete bisogno di fare uso GoogleCredential.Builder#setServiceAccountUser(String)

Prova:

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

Inoltre, una volta che avete creato una chiave account di servizio nel progetto API (dal Console API), dovrai aggiungere questo progetto all'elenco delle app di terze parti autorizzate nel cPanel. Maggiori informazioni su questo possono essere trovati here. L'ID cliente che è necessario utilizzare è quello associato alla chiave dell'account di servizio e assomiglia a <APP_ID>-<OTHER_KEY>.apps.googleusercontent.com

+0

Ciao, grazie, gli darò un vortice e postback se funziona. Ho abbandonato il progetto da allora, ma vorrei ancora sapere come farlo funzionare per riferimenti futuri. –

+0

OK Ho provato a chiamare il metodo setServiceAccountUser() e ottengo lo stesso errore. Non posso credere che Google l'abbia reso così difficile da usare! –

+0

È inoltre necessario inserire nella whitelist l'ID cliente nel cPanel del proprio dominio. Ho aggiunto come farlo nella mia risposta. Sono d'accordo 2-Legged OAuth 1 era un po 'più semplice a mio parere. HOPE possiamo ottenere qualcosa di più facile di quello con OAuth 2.0 un giorno ... – Nivco

1

Tale comportamento può verificarsi se non si è aggiunto l'utente api nel pannello di amministrazione (nel caso del pannello Documenti, credo), ad esempio in google analytics devi aggiungere un nuovo utente dove l'indirizzo email è lo stesso che hai ricevuto da API (fornito dall'account del servizio API di Google, dopo aver creato la chiave privata). In analisi sembra che questo:

example in google analytics

+0

Ciao, grazie, gli darò un vortice e lo posterò se funziona. Ho abbandonato il progetto da allora, ma vorrei ancora sapere come farlo funzionare per riferimenti futuri. –

+0

Non riesco a vedere dove sono impostati gli utenti nella Console API. –

+0

Non è una console di api è all'interno del pannello di google analytics. Ecco una semplice guida provalo: [link] (http://www.pimcore.org/wiki/display/PIMCORE/Setup+Google+Analytics+Reporting+with+OAuth2+Service+Accounts+ (da + 1.4.6)) –

5

Per quanto riguarda la 401, sembra un po 'di stranezza con l'API di Google. Trovo la prima volta che eseguo la mia app tra un po 'e poi a intervalli apparentemente casuali le ore si diffondono, ottengo sempre un 401. Al secondo o terzo turno si accede effettivamente.

Il comportamento è anche contabilizzato nel codice di esempio dell'API attività di Google here.

Avviso di questo codice:

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

}

nel codice di esempio proprio di Google hanno fatto disposizione per una prima volta 401. Potrebbe essere qualche problema di sicurezza speciale che ha bisogno di essere gestito nel codice.

0

OK, quindi ho giocato con questo e ho superato l'errore 401, ma ora sto colpendo un 403. Tuttavia, descriverò il codice che ho scritto che almeno risponde al problema 401.

Non ho modificato nessuna delle impostazioni dell'account di servizio o generato nuovamente alcun tasto ecc., È lo stesso.

Ciò che è cambiato è parte del codice e sono stato aggiornato a v3r20lv1.12.0-beta dell'API del calendario.

Il seguente codice, come sopra nel PO, rimane la stessa, cioè:

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

Il codice per ottenere una maniglia per il calendario è cambiato, ma questo è stato costretto da un cambiamento API:

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

A questo punto, posso scorrere il mio calendario e vedere gli eventi, eseguendo il seguente codice (questo stampa una sintesi dell'evento):

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

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

Ma, se provo ad aggiornare un evento, ottengo un errore Proibito 403. Alzerò un thread separato per questo e collegherò i due thread insieme.

Grazie a tutti per il vostro aiuto!

MODIFICA: here è la nuova discussione.

1

Sono uno sviluppatore di app per dispositivi mobili Android. Sto facendo un'applicazione utilizzando l'API di Google Calendar (OAuth 2.0). Ho anche affrontato questo stesso errore. Ma ora ho risolto l'errore. Sto scrivendo lo scenario e la soluzione per questo.
L'url di ottenere il Calendario degli eventi per il calendario particolare (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 questo URL, dobbiamo aggiungere il calendarId. Il formato dell'URL è;

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

Non stavo codificando il calendario prima di aggiungere all'URL. Ho codificato il calendarId e poi ho fatto la richiesta Http. Tutto è andato bene allora.

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; 

Ora gli eventi del calendario vengono restituiti nel JSON.

0

Hai richiesto l'autorizzazione per gli ambiti corretti? Dovresti sempre includere https://www.googleapis.com/auth/userinfo.profile

Problemi correlati