J'essaie de me connecter à une API REST à l'aide de l'authentification de base HTTP mais cela ne fonctionne pas et donne l'erreur
HTTP error 400: Bad Request
Voici mon code:
import urllib.parse
import urllib.request
import urllib.response
# create an authorization handler
#auth_handler = urllib.request.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib.request.HTTPBasicAuthHandler()
# Add the username and password.
# If we knew the realm, we could use it instead of None.
userName = "username"
passWord = "pass"
top_level_url = "http URL"
auth_handler.add_password(None, top_level_url, userName,passWord)
# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(auth_handler)
# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)
# use the opener to fetch a URL
try:
result = opener.open(top_level_url)
#result = urllib.request.urlopen(top_level_url)
messages = result.read()
print (messages)
except IOError as e:
print (e)
Le code python3 suivant fonctionnera:
import urllib.request
import base64
req = urllib.request.Request(download_url)
credentials = ('%s:%s' % (username, password))
encoded_credentials = base64.b64encode(credentials.encode('ascii'))
req.add_header('Authorization', 'Basic %s' % encoded_credentials.decode("ascii"))
with urllib.request.urlopen(req) as response, open(out_file_path, 'wb') as
out_file:
data = response.read()
out_file.write(data)
Mis à jour pour la compatibilité Python 3.x.
La bibliothèque requêtes offre un moyen beaucoup plus simple de faire ce genre de requête:
import requests
response = requests.get('http://service.example.com',
auth=requests.auth.HTTPBasicAuth(
'username',
'password'))
print(response.text)
Dans mes propres tests, cela fonctionne très bien, tandis qu'une solution impliquant urllib.request
(comme le vôtre, ou en utilisant le code textuellement des exemples de la documentation) ne parviendra pas à envoyer le Authentication:
entête.
urllib.request.HTTPBasicAuthHandler()
utilise par défaut HTTPPasswordMgr
. Le HTTPPasswordMgr
contient une carte qui a le mot de passe du domaine et le top_level_url
.
Lorsque vous effectuez la demande et que le serveur renvoie 401. Les en-têtes HTTP renvoyés contiennent:
Www-Authenticate: Basic realm="a-value"
HTTPPasswordMgr
recherche (utilisateur, mot de passe) le domaine renvoyé et une nouvelle demande sera envoyée avec (utilisateur, mot de passe).
Lorsque vous écrivez:
auth_handler = urllib.request.HTTPBasicAuthHandler()
# Never use None to realm parameter.
auth_handler.add_password(None, top_level_url, userName,passWord)
Vous vous attendez à ce que le serveur envoie None
royaume (mais ce n'est pas possible). Si vous souhaitez que votre serveur envoie un domaine vide dans Www-Autheader
, Tu devrais utiliser
auth_handler.add_password('', top_level_url, userName,passWord)
Vous pouvez utiliser HTTPPasswordMgrWithDefaultRealm
au lieu de HTTPPasswordMgr
pour ignorer le domaine renvoyé:
auth_handler = urllib.request.HTTPBasicAuthHandler(
urllib.request.HTTPPasswordMgr()
)
auth_handler.add_password(None, top_level_url, userName,passWord))
Si votre serveur vous envoie un code de réponse 400, avec votre exemple de code, l'authentification n'a pas été demandée.
J'utiliserais également la bibliothèque de requêtes comme recommandé par larsks, cela rend les requêtes HTTP beaucoup plus faciles.
Cela dit, voici un exemple de code de travail utilisant urllib
import urllib.parse
import urllib.request
import urllib.response
username = "my_username"
password = "my_password"
top_level_url = "URL"
# create an authorization handler
p = urllib.request.HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, top_level_url, username, password)
auth_handler = urllib.request.HTTPBasicAuthHandler(p)
opener = urllib.request.build_opener(auth_handler)
urllib.request.install_opener(opener)
try:
result = opener.open(top_level_url)
messages = result.read()
print (messages)
except IOError as e:
print (e)
Un autre détail - j'ai essayé votre propre exemple de code et je suis revenu "http 401 non autorisé", qui serait la réponse attendue en cas d'échec ou d'authentification manquante.
Cependant, vous prétendez que vous avez reçu une mauvaise requête http 400, ce qui m'amène à penser que vous avez la mauvaise URL ou qu'il y a un autre problème également