81 votes

Problème d'authentification de base avec Python urllib2

Mise à jour: basé sur Lee commentaire j'ai décidé de condenser mon code pour l'une, très simple script et l'exécuter à partir de la ligne de commande:

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)

Malheureusement, il persiste à ne pas générer l' Authorization - tête (par Wireshark) :(

Je vais avoir un problème d'envoi de l'AUTHENTIFICATION basique sur urllib2. J'ai pris un coup d'oeil à cet article, et a suivi l'exemple. Mon 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()

Je vais voir la suite sur le Fil via wireshark:

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

Vous pouvez voir l'Autorisation n'est pas envoyé, par rapport à quand j'ai envoyer une demande via curl: curl -u user:password

http://api.foursquare.com/v1/user

Pour une raison quelconque, mon code semble ne pas envoyer l'authentification quelqu'un voit ce que je suis absent?

merci

-simon

197voto

yayitswei Points 1415

Le problème pourrait être que les bibliothèques Python, par HTTP Standard, envoyez d'abord un non authentifié demande, et seulement si, il est répondu avec un 401 réessayer, sont les informations d'identification correctes envoyé. Si Foursquare serveurs ne sont pas "totalement d'authentification standard", puis les bibliothèques ne fonctionne pas.

Essayez d'utiliser des en-têtes pour faire de l'authentification:

import urllib2, base64

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

Eu le même problème que vous et a trouvé la solution de ce fil: http://forums.shopify.com/categories/9/posts/27662

5voto

dnozay Points 3672

(copier-coller / adapté de http://stackoverflow.com/a/24048772/1733117 ).

Tout d'abord, vous pouvez sous-classer urllib2.BaseHandler ou urllib2.HTTPBasicAuthHandler et implémenter http_request sorte que chaque demande possède l'en-tête Authorization approprié.

 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
 

Ensuite, si vous êtes paresseux comme moi, installez le gestionnaire globalement

 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)
 

4voto

Lee Points 1131

Le deuxième paramètre doit être un URI et non un nom de domaine. c'est à dire

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

0voto

mcepl Points 517

Je suggérerais que la solution actuelle consiste à utiliser mon paquet urllib2_prior_auth, qui résout le problème de manière satisfaisante (je travaille sur l’ inclusion dans la bibliothèque standard.

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