"Login requis" 401 message non autorisé lors de l'appel de L'API V3 Google Calendar en utilisant un compte de Service via OAuth 2.0

Tout d'abord, laissez-moi vous expliquer ce que j'essaie de faire, puisqu'il s'agit d'une question en deux parties.

je construis un service JAX-RS qui s'authentifie en interne avec un compte Google via OAuth2, afin qu'il puisse accéder et manipuler un calendrier Google. Ce service sera appelé par un site Web (Joomla), qui permettra aux utilisateurs qui se connectent sur le site d'enregistrer leur adresse e-mail avec les événements du calendrier afin qu'ils puissent recevoir des notifications par e-mail lorsque les événements sont proches. Ces utilisateurs ne connaissent pas le compte Google sous-jacent.

donc ma première question, Est d'utiliser l'authentification de compte de Service la bonne chose? En regardant le Google docs, c'est le seul cas d'utilisation qui traite de l'authentification non-humaine (donc de l'authentification de serveur à serveur).

le second problème est que j'ai écrit un code pour le faire, mais je reçois une réponse 401/non autorisée de retour l'erreur suivante de retour quand j'appelle la méthode d'exécution le flux de calendrier. Ce code a été supprimé de Google échantillon.

j'utilise v3-rev3-1.5.0-beta de L'API Google Calendar. J'ai activé l'API de calendrier dans le compte, et j'ai créé et téléchargé une clé privée, qui est utilisée dans le code ci-dessous.

j'appelle le code ci-dessous dans Eclipse localement, pas à partir d'un serveur web.

donc le premier appel que je fais est de récupérer un objet justificatif (Id est brouillé avec X's):

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("284XXXXXXXX@developer.gserviceaccount.com")
            .setServiceAccountScopes(CalendarScopes.CALENDAR)
            .setServiceAccountPrivateKeyFromP12File(new File("D:/3cd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd635e-privatekey.p12"))
            .build();

la prochaine étape est alors d'appeler L'API de calendrier, comme so (pas d'autres code):

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

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

l'appel à La liste().execute() génère l'erreur suivante:

com.Google.API.client.googleapis.json.GoogleJsonResponseException: 401 Non Autorisé { "code": 401, "erreur" : [ { "domaine": "mondial", "emplacement" : "Autorisation", "locationType" : "en-tête", "message" : "Connexion Requise", la "raison" : "requis" } ], "message" : "Connexion Requise" } à COM.Google.API.client.googleapis.json.Googlejson répondexception.à partir de(GoogleJsonResponseException.java: 159) au com.Google.API.client.googleapis.json.Googlejson répondexception.execute (GoogleJsonResponseException.java: 187) au com.Google.API.client.googleapis.service.GoogleClient.exécuteunparsed (GoogleClient.java: 115) au com.Google.API.client.http.json.JsonHttpRequest.executeUnparsed (JsonHttpRequest.java: 112) à COM.Google.API.service.calendrier.Calendrier$Calendrier$Liste $ Liste.exécuter (calendrier.java: 510) au Royaume-Uni.org.reigatepriorybowmen.Service.registreremail for allcalendarevents (Service.java: 55) au Royaume-Uni.org.reigatepriorybowmen.Service.main(Service.java: 74)

Le compte de service est configuré comme suit:

enter image description here

alors, qu'est-ce que je fais de mal?! J'ai passé des heures à chercher des solutions sur Google. espérer.

un grand merci d'avance pour votre aide.

Justin

18
demandé sur DaImTo 2012-04-11 23:52:46

6 réponses

pour ce qui est de la 401, cela semble étrange avec L'API de Google. Je trouve que la première fois que je lance mon application depuis un certain temps, et puis à des intervalles apparemment aléatoires heures réparties à distance, je reçois toujours un 401. Au deuxième ou troisième round, il se connecte.

le comportement est même pris en compte dans le code échantillon de L'API de tâche de Google ici.

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

}

dans le propre exemple de code de Google ils ont prévu pour une première fois 401. C'est peut-être un problème de sécurité qui doit être traité en code.

5
répondu Eugene van der Merwe 2012-08-07 05:41:36

un tel comportement peut se produire si vous n'avez pas ajouté l'utilisateur api dans le panneau d'administration (dans votre panneau de documents de cas je suppose), par exemple dans google analytics vous devez ajouter un nouvel utilisateur où l'adresse e-mail est la même que celle que vous avez obtenu de l'api (fourni par le compte de service de L'API Google, après la création de la clé privée). Dans google analytics, il ressemble à ceci:

example in google analytics

1
répondu Dawid D 2012-06-27 22:16:57

je pense que vous aurez besoin de spécifier le nom d'utilisateur que vous essayez d'imiter.

la façon dont vous utilisez ServiceAccount en ce moment n'est valide que pour accéder aux données relatives à votre application ou à votre compte de service lui-même. Étant donné que vous souhaitez accéder aux données du calendrier Google, vous devez être un administrateur de domaine Googleapps avec des privilèges pour accéder à l'une des données de votre utilisateur de domaine - faites-moi savoir si Je ne suis pas correct. Les données du calendrier Google appartiennent aux utilisateurs, vous devez donc spécifier quel utilisateur vous essayez de vous faire passer pour quelqu'un.

pour faire cela en utilisant Java, il semble que vous devez utiliser GoogleCredential.Builder#setServiceAccountUser (String)

s'il vous Plaît essayer:

GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
        .setJsonFactory(JSON_FACTORY)
        .setServiceAccountId("284XXXXXXXX@developer.gserviceaccount.com")
        .setServiceAccountScopes(CalendarScopes.CALENDAR)
        .setServiceAccountPrivateKeyFromP12File(new File("/path/to/privatekey.p12"))
        .setServiceAccountUser("user@domain.com")
        .build();
ici. L'Identification Du Client" vous devez utiliser est celui lié au Compte de Service de clé et ressemble à <APP_ID>-<OTHER_KEY>.apps.googleusercontent.com

1
répondu Nicolas Garnier 2012-07-25 18:15:48

je suis développeur D'applications mobiles Android. Je fais une application en utilisant Google Calendar API (outh 2.0). J'ai également fait face à cette même erreur. Mais maintenant, j'ai résolu l'erreur. Je suis en train d'écrire le scénario et la solution pour elle.

L'url d'obtenir le Calendrier des Événements de l'agenda particulier (Application Mobile API):

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

dans cette url, nous devons ajouter le calendarId. Le format de l'url est;

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

Je n'encodais pas le calendaride avant ajoutant à l'url. J'ai encodé le calendarId puis fait la requête Http. Tout s'est bien passé ensuite.

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;

maintenant les événements du calendrier sont retournés dans le JSON.

1
répondu Khushboo 2013-02-15 11:14:17

OK, donc j'ai joué avec ça et j'ai passé l'erreur 401, mais je suis maintenant sur un 403. Cependant, je vais détailler le code que j'ai écrit qui répond au moins au problème 401.

Je n'ai pas modifié les paramètres du compte de service ni recréé les clés, etc., qui sont toutes les mêmes.

Ce qui a le changement est une partie du code, et j'ai mis à jour v3r20lv1.12.0-bêta de L'API de calendrier.

le code ci-dessous, comme détaillé ci-dessus dans L'OP, reste le même, i.e.:

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("284XXXXXXXX@developer.gserviceaccount.com")
        .setServiceAccountScopes(CalendarScopes.CALENDAR)
        .setServiceAccountPrivateKeyFromP12File(new File("D:/3cd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd635e-privatekey.p12"))
        .build();

le code pour obtenir une poignée pour le calendrier a changé, mais cela a été forcé par un changement D'API:

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

a ce point, je peux itérer à travers mon calendrier et voir les événements, en exécutant le code suivant (ceci imprime un résumé d'événement):

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

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

mais, si j'essaie de mettre à jour un événement, j'obtiens une erreur 403 interdite. Je vais élever un thread séparé pour cela, et permettra de relier les deux fils ainsi.

Merci à tous pour votre aide!

EDIT: ici est le nouveau fil.

0
répondu Justin Phillips 2017-05-23 12:34:15

avez-vous demandé la permission pour les portées appropriées? Vous devez toujours inclure https://www.googleapis.com/auth/userinfo.profile

0
répondu Kees de Kooter 2013-05-02 09:06:08