Je joue avec l'API Google Checkout et je veux l'intégrer dans une application Django. Je dois publier des données sur Google à l'aide de l'authentification http de base. J'ai testé cela avec curl comme ceci:

curl -d "$(cat mytest.xml)" -u username:password https://url

Et cela publie le contenu de mon fichier XML de test sur Google. Et ça marche bien!

Mais j'ai des problèmes pour porter cette simple ligne sur Python. J'ai réussi plusieurs façons différentes (httplib2, urllib2, pycurl) de se connecter avec un mot de passe et de publier quelque chose, mais la réponse est toujours 400 BAD REQUEST.

Existe-t-il un équivalent python pour publier un bloc de texte sur un serveur d'authentification HTTP Basic? Je cours hors des murs pour me cogner la tête.


Toutes mes excuses pour ne pas avoir ajouté de code. Voici quelques-uns de mes plus grands succès. Dans chacun, DATA est une chaîne XML. URL, USERNAME et PASSWORD sont constants.

req = urllib2.Request(URL)
req.add_header("Authorization", "Basic %s" % base64.encodestring('%s:%s'%(USERNAME, PASSWORD)))
u = urllib2.urlopen(req, DATA)

Me donne une belle HTTP Error 400: Bad Request


passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, URL, USERNAME, PASSWORD)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
pagehandle = urllib2.urlopen(URL, DATA)

Donne HTTP Error 401: Unauthorized


pycurl.global_init(pycurl.GLOBAL_DEFAULT)
c = pycurl.Curl()
c.setopt(pycurl.URL, URL)
c.setopt(pycurl.USERPWD, "%s:%s" % (USERNAME,PASSWORD))
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"])
c.setopt(pycurl.POSTFIELDS, DATA)
b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.perform()

Semble avoir du mal à passer la chaîne DATA en tant que POSTFIELD. J'ai essayé de urllib.urlencode() ing DATA de plusieurs manières différentes mais


h = httplib2.Http()
h.add_credentials(USERNAME, PASSWORD)
print = h.request(URL, "POST", body=base64.encodestring(DATA))

Les informations d'identification ne semblent rien faire - je reçois un message non autorisé de Google.

Il y en a plus, mais ils sont tous basés sur ceux-ci.

9
Oli 15 déc. 2011 à 16:10

3 réponses

Meilleure réponse

J'ai eu des turbulences similaires avec les packages stdlib, jusqu'à ce que quelqu'un pointe les impressionnantes requêtes qui prend en charge l'authentification de base Http et d'autres authentifications signifie tout droit sorti de la boîte! Et il a une belle et simple API ça fait mal!

requests.post(url, data=DATA, headers=HEADERS_DICT, auth=(username, password))

Il prend en charge une foule d'autres fonctionnalités nécessaires (par exemple HTTPS, authentification Digest, etc.) Veuillez vérifier si vous devez ...

12
Oli 10 oct. 2012 à 09:46

Voidspace a un excellent article sur l'utilisation de l'authentification de base avec urllib2. J'ai copié l'extrait de code approprié ci-dessous, modifié pour utiliser POST.

import urllib2

theurl = 'http://www.someserver.com/toplevelurl/somepage.htm'
username = 'johnny'
password = 'XXXXXX'

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, theurl, username, password)

authhandler = urllib2.HTTPBasicAuthHandler(passman)

opener = urllib2.build_opener(authhandler)

urllib2.install_opener(opener)

pagehandle = urllib2.urlopen(theurl, open("mytext.xml").read())

Sans voir votre code, il est difficile de dire pourquoi vous obtiendrez une réponse 400.

2
Andrew Wilkinson 15 déc. 2011 à 13:11

Lors de l'édition de mon article pour inclure une source, j'ai pensé que j'aurais une autre fissure à httplib2 (principalement parce qu'il est relativement petit et joli par rapport aux autres) et j'ai remarqué qu'il y avait un bogue béant en ce que sa méthode add_credentials(..) ne fait rien. Vous pouvez contourner cela en spécifiant l'en-tête (comme je l'ai fait avec urllib2) comme ceci:

resp, content = httplib2.Http().request(URL, "POST", body=DATA, headers={
    "Authorization": "Basic %s" % base64.encodestring('%s:%s' %(USERNAME, PASSWORD)
})

Et ça marche.

2
Oli 15 déc. 2011 à 13:03