2010-03-09 7 views
76

Update: basierend auf Lees Kommentar entschied ich meinen Code auf ein wirklich einfaches Skript zu kondensieren und es von der Kommandozeile:Pythons urllib2 Grund Auth Problem

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) 

Leider erzeugt es immer noch nicht den Authorization Kopf . (pro Wireshark) :(

ich habe ein Problem Grund AUTH über urllib2 Senden nahm ich einen Blick auf this article und folgte dem Beispiel Mein Code:.

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() 
Folgendes auf dem Draht über wireshark 10

Ich sehe:

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

Sie die Berechtigung sehen kann, wird nicht gesendet, wenn ich gegen eine Anfrage per curl senden: 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: */* 

Für einige Grund scheint mein Code die Authentifizierung nicht zu senden - jeder sieht was ich vermisse?

dank

-Simon

+1

Ich frage mich, ob das Problem ist, dass die Website einen Header "WWW-Authenticate" nicht zurückgibt. Sie können dies überprüfen mit 'try: urllib2.urlopen (req) außer urllib2.HTTPError, e: print e.headers '[Siehe diese SO-Post-Antwort] (http: // stackoverflow.com/a/9698319/1020470). –

Antwort

186

könnte das Problem sein, dass die Python-Bibliotheken, per HTTP-Standard zunächst eine nicht authentifizierte Anforderung senden, und nur dann, wenn es mit einem 401 Neuversuch, sind die richtigen Anmeldeinformationen gesendet beantwortet wird. Wenn die Foursquare-Server keine vollständige Standardauthentifizierung durchführen, funktionieren die Bibliotheken nicht.

Versuchen Header mit Authentifizierung zu tun:

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) 

Hatte das gleiche Problem wie du und die Lösung aus diesem Thread gefunden: http://forums.shopify.com/categories/9/posts/27662

+3

Danke Mann, total gerettet mein Tag! – Ulf

+0

HTTP-Fehler 505: HTTP-Version nicht unterstützt; ( –

+0

Funktioniert mit Paypal-Authentifizierung (um access_token) auch. Vielen Dank, Kumpel! – DerShodan

4

Der zweite Parameter ein URI, der kein Domänenname sein muss. das heißt

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

Danke - ich hätte erwähnen sollen, dass ich das in einer Anzahl verschiedener Kombinationen probiert habe: http: // api.foursquare.com, api.foursquare.com, http: // api.foursquare.com/v1/, aber das scheint das Problem nicht zu lösen. – Simon

+0

Ich habe gerade versucht dies gegen einen lokalen Server hier, die grundlegende Auth benötigt und mit der URL in der add_password hat es gut funktioniert. Ich würde daher vorschlagen, dass etwas anderes im Gange ist. – Lee

+0

Dies funktioniert nur, wenn die HTTP-Antwort den Code 401 Unauthorized ** _ und _ ** die Kopfzeile ''WWW-Authenticate' 'enthält; siehe [diese Antwort nach SO] (http://stackoverflow.com/a/9698319/1020470). –

4

(copy-paste/von https://stackoverflow.com/a/24048772/1733117 angepasst).

Zuerst können Sie die Unterklasse urllib2.BaseHandler oder urllib2.HTTPBasicAuthHandler und implementieren http_request, so dass jede Anfrage die entsprechenden Authorization Header hat.

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 

Dann, wenn Sie faul wie ich sind, installieren Sie den Handler global

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) 
0

Ich würde vorschlagen, dass die aktuelle Lösung ist mein Paket urllib2_prior_auth zu verwenden, die dieses ziemlich gut löst (ich auf inclusion arbeiten Die Standard-Bibliothek

+0

W ille es erlauben, URLs wie' urllib2.urlopen zu öffnen ('http: // USER: PASS @ Beispiel .com/path/') ' – ddofborg

+0

Dies ist ein anderes Problem.Sie sind sicher, dass dies nicht mit dem Standard' 'urllib2'' funktioniert? – mcepl

+0

Nein, es funktioniert nicht :( – ddofborg

2

Hier ist, was ich verwende, um mit einem ähnlichen Problem umzugehen, das ich beim Versuch, auf MailChimp-API zuzugreifen, begegnet ist.Dies tut das gleiche, gerade formatiert netter.

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) 
+0

Großartig, das funktioniert mit Python 2.6. 6 – dirceusemighini