2012-09-18 7 views
11

He instalado y ejecuto con éxito el Google Drive Quick Start application called DriveCommandLine. También lo he adaptado un poco para OBTENER información de archivo para uno de los archivos en mi cuenta de Drive.Google Drive/OAuth: no se puede encontrar la forma de obtener GoogleCredentials reutilizables

Lo que me gustaría hacer ahora es guardar las credenciales de alguna manera y volver a utilizarlas sin que el usuario tenga que visitar una página web cada vez para obtener un código de autorización. He revisado this page con instrucciones para Recuperar y Usar credenciales de OAuth 2.0. Con el fin de utilizar la clase de ejemplo (MyClass), he modificado la línea en DriveCommandLine donde se crea una instancia del objeto de credenciales:

Credential credential = MyClass.getCredentials(code, ""); 

Esto se traduce en la siguiente excepción ser arrojado:

java.lang.NullPointerException 
    at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187) 
    at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84) 
    at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247) 
    at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168) 
    at googledrive.MyClass.getFlow(MyClass.java:145) 
    at googledrive.MyClass.exchangeCode(MyClass.java:166) 
    at googledrive.MyClass.getCredentials(MyClass.java:239) 
    at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56) 
    at googledrive.DriveCommandLine.main(DriveCommandLine.java:115) 

I' He estado mirando estas API (Google Drive y OAuth) durante 2 días y he progresado muy poco. Realmente agradecería algo de ayuda con el error anterior y el problema de obtener credenciales persistentes en general.

Toda esta estructura me parece innecesariamente complicada. ¿A alguien le importa explicar por qué no puedo simplemente crear un objeto credencial simple al pasar mi nombre de usuario y contraseña de Google?

Gracias, Brian O Carroll, Dublín, Irlanda

* Actualización *

Ok, he llegado sólo alrededor del error anterior y ahora tengo una nueva.

La forma en que solucioné el primer problema fue modificando MyClass.getFlow(). En lugar de crear un objeto GoogleClientServices de un archivo JSON, he utilizado una versión diferente de GoogleAuthorizationCodeFlow.Builder que le permite introducir el ID de cliente y el cliente secreta directamente como Strings:

flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build(); 

El problema que tengo ahora es que me sale el siguiente error al intentar utilizar el flujo (GoogleAuthorizationCodeFlow objeto) para cambiar el código de autorización para las credenciales objeto:

An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request 
{ 
    "error" : "invalid_scope" 
} 
googledrive.MyClass$CodeExchangeException 
     at googledrive.MyClass.exchangeCode(MyClass.java:185) 
     at googledrive.MyClass.getCredentials(MyClass.java:262) 
     at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56) 
     at googledrive.DriveCommandLine.main(DriveCommandLine.java:115) 

¿hay algún otro ámbito que debería usar para esto? Actualmente estoy usando la matriz de ámbitos proporcionada con MyClass:

private static final List<String> SCOPES = Arrays.asList(
     "https://www.googleapis.com/auth/drive.file", 
     "https://www.googleapis.com/auth/userinfo.email", 
     "https://www.googleapis.com/auth/userinfo.profile"); 

Gracias!

Respuesta

13

Siento tu dolor. Tengo dos meses y sigo sorprendiéndome.

Algunos de mis aprendizajes ...

  • Al solicitar los permisos de usuario, especifique "desconectado = true". Esto hará que ("a veces" sic) devuelva un refreshtoken, que es tan bueno como una contraseña con permisos restringidos. Puede almacenar esto y reutilizarlo en cualquier momento (hasta que el usuario lo revoque) para obtener un token de acceso.

  • Mi impresión es que los SDK de Google son más una molestia que una ayuda. Uno por uno, he dejado de usarlos y ahora llamo a la API REST directamente.

  • En su último punto, puede (simplemente) utilizar el protocolo de inicio de sesión de cliente de Google para acceder a la generación anterior de API. Sin embargo, esto está totalmente obsoleto y pronto se apagará. OAuth está diseñado para otorgar un control detallado de la autorización que es intrínsecamente compleja. Entonces, aunque estoy de acuerdo en que es complicado, no creo que sea innecesario. Vivimos en un mundo complicado :-)

Sus minas y experiencias muestran que la comunidad de desarrollo todavía está en necesidad de un documento y recetas consolidada para conseguir estas cosas en nuestros espejos retrovisores para poder centrarse en la tarea a mano.

+0

Gracias pinoyyid, lo siento, accidentalmente añadió una edición/actualización de su puesto en lugar de la mía. ¡Todavía me estoy acostumbrando a publicar aquí! Intentaré implementar sus sugerencias y le dejaré saber cómo va eso. PD: Desafortunadamente, no tengo 2 meses para trabajar en esto. ¡Estoy molesto porque ya he pasado 2 días! : -/ –

+0

Con respecto al retorno de frefreshtoken. Creé una aplicación de servidor que debe ejecutarse sin interacción del usuario después de configurada.Pero hace algunos días (estuvo funcionando durante 2 meses sin problemas) se vio que se abrieron varias páginas de Auth en el servidor para solicitar acceso a la aplicación para usar Google Drive. Incluso si estaba pidiendo Auth, aún funcionaba. ¿Alguna pista de por qué ocurre esto? –

+0

probablemente sea una pregunta separada. También veo esto y lo atribuyo a Google que expira aleatoriamente el token de actualización. Compruebe si hay una subvención de 400 inválidos en sus registros para ver si esa es la causa. ¿Es posible que su aplicación solicite un token de actualización desde más de un lugar? Creo que si ese es el caso, los nuevos tokens de actualización pueden caducar los antiguos. – pinoyyid

1

Ok, finalmente he resuelto el segundo problema anterior y finalmente estoy obteniendo un objeto GoogleCredential que funciona con un token de acceso y un token de actualización.

Seguí tratando de resolver el problema de ámbitos modificando la lista de ámbitos en MyClass (el que gestiona las credenciales). Al final tuve que ajustar los ámbitos en mi versión modificada de DriveCommandLine (la que se utilizó originalmente para obtener un código de autorización). He añadido 2 alcances de Oauth2Scopes:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
    httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, 
    Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE)) 
    .setAccessType("offline").setApprovalPrompt("force").build(); 

Adición de los alcances de la información del usuario me permitió la identificación de usuario más adelante en MiClase. Ahora puedo usar el ID de usuario para almacenar las credenciales en una base de datos para su reutilización (sin tener que hacer que el usuario vaya a una URL cada vez). También configuré el tipo de acceso a "fuera de línea" como lo sugiere pinoyyid.

3

Oath2Scopes se importa como sigue:

import com.google.api.services.oauth2.Oauth2Scopes; 

Es necesario tener el archivo jar 'google-api-services-OAuth2-v2-rev15-1.8.0-beta.jar' en su camino a clase acceder a ese paquete Se puede descargar here.

No, no sé cómo obtener credenciales sin tener que visitar la URL de autorización al menos una vez y copiar el código. Modifiqué MyClass para almacenar y recuperar credenciales de una base de datos (en mi caso, es una tabla simple que contiene userid, accesstoken y refreshtoken). De esta manera, solo tengo que obtener el código de autorización una vez y una vez que obtenga los tokens de acceso/actualización, puedo reutilizarlos para crear un objeto GoogleCredential. Así es como Imake el objeto GoogleCredential:

GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory) 
      .setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build(); 
    credential.setAccessToken(accessToken); 
    credential.setRefreshToken(refreshToken); 

Simplemente introduzca su ClientID, clientsecret, accessToken y refreshToken anteriormente.

Realmente no tengo mucho tiempo para separar y poner en orden todo el código para publicarlo aquí, pero si sigues teniendo problemas, házmelo saber y veré lo que puedo hacer. Aunque, de hecho estás pidiendo instrucciones a un ciego. ¡Mi comprensión de todo este sistema es muy incompleta!

Saludos, Brian

Cuestiones relacionadas