Me pregunto cuál es la mejor y más fácil manera de autenticar al usuario de la API de datos de Google en una aplicación de escritorio.API de datos de Google: cómo hacer la autenticación para aplicaciones de escritorio
Leo a través del docs y parece que mis opciones son ClientLogin u OAuth.
Para ClientLogin, parece que tengo que implementar la interfaz de usuario para el inicio de sesión/contraseña (y cosas relacionadas como guardar esto en alguna parte, etc.). Realmente me pregunto si hay algo más de soporte allí que pueda mostrar alguna pantalla de inicio de sesión/contraseña predeterminada y use el llavero del sistema operativo para almacenar la contraseña, etc. Me pregunto por qué ese apoyo no está allí. ¿No sería ese el procedimiento estándar? Al dejar esa implementación al desarrollador (bueno, la posibilidad de dejar esa impl al desarrollador es buena, por supuesto), creo que mucha gente ha encontrado soluciones muy feas aquí (cuando solo querían hackear un pequeño script)
OAuth parece ser la mejor solución. Sin embargo, parece que falta un código y/o la mayoría del código que encontré parece ser solo relevante para las aplicaciones web. Esp., Seguí la documentación y obtuve here. Ya en la introducción, habla sobre la aplicación web. Luego, más adelante, debo especificar una URL de devolución de llamada que no tiene sentido para una aplicación de escritorio. También me pregunto qué clave de consumidor/secreto debo poner, ya que tampoco tiene sentido para una aplicación de escritorio (especialmente para una de código abierto). Busqué un poco y se dijo here (on SO) que debería usar "anónimo"/"anónimo" como la clave/secreto del consumidor; pero, ¿dónde dice eso en la documentación de Google? ¿Y cómo obtengo el token después de que el usuario se haya autenticado?
¿Hay algún código de muestra? (No con un nombre de usuario/contraseña codificada, pero con un método de autenticación completa reutilizable.)
Gracias, Albert
Mi código hasta ahora:
import gdata.gauth
import gdata.contacts.client
CONSUMER_KEY = 'anonymous'
CONSUMER_SECRET = 'anonymous'
SCOPES = [ "https://www.google.com/m8/feeds/" ] # contacts
client = gdata.contacts.client.ContactsClient(source='Test app')
import BaseHTTPServer
import SocketServer
Handler = BaseHTTPServer.BaseHTTPRequestHandler
httpd = BaseHTTPServer.HTTPServer(("", 0), Handler)
_,port = httpd.server_address
oauth_callback_url = 'http://localhost:%d/get_access_token' % port
request_token = client.GetOAuthToken(
SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
loginurl = request_token.generate_authorization_url(google_apps_domain=None)
loginurl = str(loginurl)
import webbrowser
webbrowser.open(loginurl)
Sin embargo, esto no funciona . Obtengo este error:
Sorry, you've reached a login page for a domain that isn't using Google Apps. Please check the web address and try again.
No entiendo muy bien eso. Por supuesto que no uso Google Apps.
Ah, que el error proviene de google_apps_domain=None
en generate_authorization_url
. Deja que la distancia (es decir, justo loginurl = request_token.generate_authorization_url()
y funciona hasta el momento
Mi código actual:.
import gdata.gauth
import gdata.contacts.client
CONSUMER_KEY = 'anonymous'
CONSUMER_SECRET = 'anonymous'
SCOPES = [ "https://www.google.com/m8/feeds/" ] # contacts
client = gdata.contacts.client.ContactsClient(source='Test app')
import BaseHTTPServer
import SocketServer
httpd_access_token_callback = None
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/get_access_token?"):
global httpd_access_token_callback
httpd_access_token_callback = self.path
self.send_response(200)
def log_message(self, format, *args): pass
httpd = BaseHTTPServer.HTTPServer(("", 0), Handler)
_,port = httpd.server_address
oauth_callback_url = 'http://localhost:%d/get_access_token' % port
request_token = client.GetOAuthToken(
SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
loginurl = request_token.generate_authorization_url()
loginurl = str(loginurl)
print "opening oauth login page ..."
import webbrowser; webbrowser.open(loginurl)
print "waiting for redirect callback ..."
while httpd_access_token_callback == None:
httpd.handle_request()
print "done"
request_token = gdata.gauth.AuthorizeRequestToken(request_token, httpd_access_token_callback)
# Upgrade the token and save in the user's datastore
access_token = client.GetAccessToken(request_token)
client.auth_token = access_token
que abrirá la página de Google OAuth con la pista en la parte inferior:
This website has not registered with Google to establish a secure connection for authorization requests. We recommend that you deny access unless you trust the website.
Se Todavía no funciona, sin embargo. Cuando trato de acceder a los contactos (es decir, solo un client.GetContacts()
), aparece este error:
gdata.client.Unauthorized: Unauthorized - Server responded with: 401, <HTML>
<HEAD>
<TITLE>Token invalid - AuthSub token has wrong scope</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Token invalid - AuthSub token has wrong scope</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
Ok, parece que realmente había establecido el alcance incorrecto. Cuando uso http
en lugar de https
(es decir, SCOPES = [ "http://www.google.com/m8/feeds/" ]
), funciona.
Pero realmente me gustaría usar https. Me pregunto cómo puedo hacer eso.
Además, otro problema con esta solución:
En la lista de acceso autorizado a mi cuenta de Google, ahora tengo un montón de tales entradas localhost:
localhost:58630 — Google Contacts [ Revoke Access ]
localhost:58559 — Google Contacts [ Revoke Access ]
localhost:58815 — Google Contacts [ Revoke Access ]
localhost:59174 — Google Contacts [ Revoke Access ]
localhost:58514 — Google Contacts [ Revoke Access ]
localhost:58533 — Google Contacts [ Revoke Access ]
localhost:58790 — Google Contacts [ Revoke Access ]
localhost:59012 — Google Contacts [ Revoke Access ]
localhost:59191 — Google Contacts [ Revoke Access ]
Me pregunto cómo Puedo evitar que haga tales entradas.
Cuando uso xoauth_displayname
, muestra ese nombre en su lugar, pero aún hace varias entradas (probablemente porque la URL sigue siendo en su mayoría diferente (debido al puerto) cada vez). ¿Cómo puedo evitar eso?
Mi código actual es ahora Github.
también me pregunto, dónde, cómo y por cuánto tiempo debo almacenar el token de acceso y/o el token pedido, por lo que el usuario no se le pide siempre una y otra vez cada vez que el usuario inicia la aplicación.
La autorización por parte del usuario - exactamente cómo se vería eso ¿me gusta? ¿Abrí un webbrowser externo y de alguna manera volví a verificar con frecuencia si el token estaba autorizado? En el código de ejemplo, realmente no veo dónde se abre el navegador web. – Albert
Además, parece que gdata lib ya viene con funciones para OAuth. ¿Entonces supongo que no necesito otra lib para eso? ¿O qué proporciona python-oauth2 además de lo que ya tengo con gdata? – Albert
OAuth de tres patas funciona de la siguiente manera: 1. Solicita un token y un token secret del proveedor (Google) 2.Abre un navegador web para el usuario y lo lleva a la URL de autorización del proveedor, donde el usuario puede confirmar que desea darle acceso y le devuelve un código de verificación. El sitio del proveedor puede devolverle la llamada a través de una URL que proporciona el verificador, o darle al usuario el código de verificador que necesita. 3. con el token original y el verificador, puede adquirir su token final del proveedor. – ldx