52 votes

Comment accéder à un service Google App Engine authentifié à partir d'un client python (non web) ?

J'ai une application Google App Engine - http://mylovelyapp.appspot.com/ Il a une page - mylovelypage

Pour l'instant, la page ne fait que self.response.out.write('OK')

Si je lance le Python suivant sur mon ordinateur :

import urllib2
f = urllib2.urlopen("http://mylovelyapp.appspot.com/mylovelypage")
s = f.read()
print s
f.close()

Il imprime "OK".

le problème est que si j'ajoute login:required à cette page dans le yaml de l'application.

puis ceci imprime le HTML de la page de connexion aux comptes Google

J'ai essayé les approches d'authentification "normales", par exemple.

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()

auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(None,
                          uri='http://mylovelyapp.appspot.com/mylovelypage',
                          user='billy.bob@gmail.com',
                          passwd='billybobspasswd')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)

Mais cela ne fait aucune différence - je récupère toujours le HTML de la page de connexion.

J'ai essayé L'API d'authentification ClientLogin de Google mais je n'arrive pas à le faire fonctionner.

h = httplib2.Http()

auth_uri = 'https://www.google.com/accounts/ClientLogin'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
myrequest = "Email=%s&Passwd=%s&service=ah&source=DALELANE-0.0" % ("billy.bob@gmail.com", "billybobspassword")
response, content = h.request(auth_uri, 'POST', body=myrequest, headers=headers)

if response['status'] == '200':
    authtok = re.search('Auth=(\S*)', content).group(1)

    headers = {}
    headers['Authorization'] = 'GoogleLogin auth=%s' % authtok.strip()
    headers['Content-Length'] = '0'

    response, content = h.request("http://mylovelyapp.appspot.com/mylovelypage", 
                                  'POST', 
                                  body="", 
                                  headers=headers)

    while response['status'] == "302":        
        response, content = h.request(response['location'], 'POST', body="", headers=headers) 

    print content

Il semble que je puisse obtenir un jeton correctement, mais les tentatives pour l'utiliser dans l'en-tête lorsque j'appelle 'mylovelypage' ne me renvoient que le HTML de la page de connexion. :-(

Quelqu'un peut-il m'aider, s'il vous plaît ?

Pourrais-je utiliser le Bibliothèque client GData pour faire ce genre de choses ? D'après ce que j'ai lu, je pense qu'il devrait être capable d'accéder aux applications App Engine, mais je n'ai pas réussi non plus à faire fonctionner l'authentification pour les applications App Engine.

Si vous pouvez m'indiquer des exemples, des articles, ou même des mots-clés que je devrais pour me permettre de démarrer, serait très apprécié.

Merci !

39voto

Nick Johnson Points 79909

Appcfg.py, l'outil qui télécharge des données vers App Engine doit faire exactement cela pour s'authentifier auprès du serveur App Engine. La fonctionnalité pertinente est abstraite dans appengine_rpc.py. En bref, la solution est la suivante :

  1. Utilisez le API Google ClientLogin afin d'obtenir un jeton d'authentification. appengine_rpc.py fait cela en _GetAuthToken
  2. Envoyez le jeton d'authentification à une URL spéciale sur votre application App Engine. Cette page renvoie alors un cookie et une redirection 302. Ignorez la redirection et stockez le cookie. appcfg.py fait ceci dans _GetAuthCookie
  3. Utilisez le cookie renvoyé dans toutes les demandes futures.

Vous pouvez également consulter _Authentiquer pour voir comment appcfg traite les différents codes de retour de ClientLogin, et _GetOpener pour voir comment appcfg crée un OpenerDirector urllib2 qui ne suit pas les redirections HTTP. Vous pouvez également utiliser les classes AbstractRpcServer et HttpRpcServer dans leur intégralité, car elles font à peu près tout ce dont vous avez besoin.

34voto

dalelane Points 1338

Merci à Arachnid pour la réponse - cela a fonctionné comme suggéré.

voici une copie simplifiée du code, au cas où elle serait utile à la prochaine personne qui essaiera !

import os
import urllib
import urllib2
import cookielib

users_email_address = "billy.bob@gmail.com"
users_password      = "billybobspassword"

target_authenticated_google_app_engine_uri = 'http://mylovelyapp.appspot.com/mylovelypage'
my_app_name = "yay-1.0"

# we use a cookie to authenticate with Google App Engine
#  by registering a cookie handler here, this will automatically store the 
#  cookie returned when we use urllib2 to open http://currentcost.appspot.com/_ah/login
cookiejar = cookielib.LWPCookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
urllib2.install_opener(opener)

#
# get an AuthToken from Google accounts
#
auth_uri = 'https://www.google.com/accounts/ClientLogin'
authreq_data = urllib.urlencode({ "Email":   users_email_address,
                                  "Passwd":  users_password,
                                  "service": "ah",
                                  "source":  my_app_name,
                                  "accountType": "HOSTED_OR_GOOGLE" })
auth_req = urllib2.Request(auth_uri, data=authreq_data)
auth_resp = urllib2.urlopen(auth_req)
auth_resp_body = auth_resp.read()
# auth response includes several fields - we're interested in 
#  the bit after Auth= 
auth_resp_dict = dict(x.split("=")
                      for x in auth_resp_body.split("\n") if x)
authtoken = auth_resp_dict["Auth"]

#
# get a cookie
# 
#  the call to request a cookie will also automatically redirect us to the page
#   that we want to go to
#  the cookie jar will automatically provide the cookie when we reach the 
#   redirected location

# this is where I actually want to go to
serv_uri = target_authenticated_google_app_engine_uri

serv_args = {}
serv_args['continue'] = serv_uri
serv_args['auth']     = authtoken

full_serv_uri = "http://mylovelyapp.appspot.com/_ah/login?%s" % (urllib.urlencode(serv_args))

serv_req = urllib2.Request(full_serv_uri)
serv_resp = urllib2.urlopen(serv_req)
serv_resp_body = serv_resp.read()

# serv_resp_body should contain the contents of the 
#  target_authenticated_google_app_engine_uri page - as we will have been 
#  redirected to that page automatically 
#
# to prove this, I'm just gonna print it out
print serv_resp_body

1voto

ryan Points 1520

Pour ceux qui ne parviennent pas à faire fonctionner ClientLogin, essayez le moteur d'application Support OAuth .

0voto

Sean O Donnell Points 601

Je ne suis pas trop familier avec AppEngine, ou Googles web apis, mais pour une approche par force brute vous pourriez écrire un script avec quelque chose comme mechanize ( http://wwwsearch.sourceforge.net/mechanize/ ) pour simplement passer par le processus de connexion avant de commencer à faire le vrai travail du client.

-1voto

Je ne suis pas un expert en python ou en moteur d'application. Mais avez-vous essayé de suivre l'exemple d'application à http://code.google.com/appengine/docs/gettingstarted/usingusers.html . J'en ai créé un à http://quizengine.appspot.com Il semblait fonctionner correctement avec l'authentification Google et tout le reste. C'est juste une suggestion, mais regardez dans le guide de démarrage. Allez-y doucement si la suggestion vous semble naïve :) Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X