Python urllib2 Basic Auth Problem

Actualización: basado en el comentario de Lee, decidí condensar mi código en un script realmente simple y ejecutarlo desde la línea de comandos:

import urllib2 import sys username = sys.argv[1] password = sys.argv[2] url = sys.argv[3] print("calling %s with %s:%s\n" % (url, username, password)) passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, url, username, password) urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman))) req = urllib2.Request(url) f = urllib2.urlopen(req) data = f.read() print(data) 

Desafortunadamente, todavía no generará el encabezado de Authorization (por Wireshark) 🙁

Tengo un problema al enviar AUTH básico a través de urllib2. Eché un vistazo a este artículo y seguí el ejemplo. Mi código:

 passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, "api.foursquare.com", username, password) urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman))) req = urllib2.Request("http://api.foursquare.com/v1/user") f = urllib2.urlopen(req) data = f.read() 

Estoy viendo lo siguiente en el Wire a través de wireshark:

 GET /v1/user HTTP/1.1 Host: api.foursquare.com Connection: close Accept-Encoding: gzip User-Agent: Python-urllib/2.5 

Puede ver que la Autorización no se envía, en comparación con cuando envío una solicitud a través de curl: curl -u user:password http://api.foursquare.com/v1/user

 GET /v1/user HTTP/1.1 Authorization: Basic =SNIP= User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3 Host: api.foursquare.com Accept: */* 

Por alguna razón, mi código parece no enviar la autenticación: ¿alguien ve lo que me estoy perdiendo?

Gracias

-simon

El problema podría ser que las bibliotecas de Python, por HTTP-Standard, primero envíen una solicitud no autenticada, y luego solo si se responde con un rebash 401, se envían las credenciales correctas. Si los servidores de Foursquare no hacen una “autenticación totalmente estándar”, las bibliotecas no funcionarán.

Trate de usar encabezados para hacer la autenticación:

 import urllib2, base64 request = urllib2.Request("http://api.foursquare.com/v1/user") base64string = base64.b64encode('%s:%s' % (username, password)) request.add_header("Authorization", "Basic %s" % base64string) result = urllib2.urlopen(request) 

Tuvo el mismo problema que usted y encontró la solución en este hilo: http://forums.shopify.com/categories/9/posts/27662

(copiar y pegar / adaptado de https://stackoverflow.com/a/24048772/1733117 ).

Primero puede subclase urllib2.BaseHandler o urllib2.HTTPBasicAuthHandler , e implementar http_request para que cada solicitud tenga el encabezado de Authorization adecuado.

 import urllib2 import base64 class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler): '''Preemptive basic auth. Instead of waiting for a 403 to then retry with the credentials, send the credentials if the url is handled by the password manager. Note: please use realm=None when calling add_password.''' def http_request(self, req): url = req.get_full_url() realm = None # this is very similar to the code from retry_http_basic_auth() # but returns a request object. user, pw = self.passwd.find_user_password(realm, url) if pw: raw = "%s:%s" % (user, pw) auth = 'Basic %s' % base64.b64encode(raw).strip() req.add_unredirected_header(self.auth_header, auth) return req https_request = http_request 

Entonces, si eres perezoso como yo, instala el controlador globalmente

 api_url = "http://api.foursquare.com/" api_username = "johndoe" api_password = "some-cryptic-value" auth_handler = PreemptiveBasicAuthHandler() auth_handler.add_password( realm=None, # default realm. uri=api_url, user=api_username, passwd=api_password) opener = urllib2.build_opener(auth_handler) urllib2.install_opener(opener) 

Esto es lo que estoy usando para tratar un problema similar que encontré al intentar acceder a la API de MailChimp. Esto hace lo mismo, simplemente formateado mejor.

 import urllib2 import base64 chimpConfig = { "headers" : { "Content-Type": "application/json", "Authorization": "Basic " + base64.encodestring("hayden:MYSECRETAPIKEY").replace('\n', '') }, "url": 'https://us12.api.mailchimp.com/3.0/'} #perform authentication datas = None request = urllib2.Request(chimpConfig["url"], datas, chimpConfig["headers"]) result = urllib2.urlopen(request) 

El segundo parámetro debe ser un URI, no un nombre de dominio. es decir

 passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, "http://api.foursquare.com/", username, password) 

Sugeriría que la solución actual es usar mi paquete urllib2_prior_auth que resuelve esto bastante bien (trabajo en la inclusión a la biblioteca estándar).