Python, HTTPS GET mit Basisauthentifizierung

88

Ich versuche, ein HTTPS-GET mit grundlegender Authentifizierung unter Verwendung von Python durchzuführen. Ich bin sehr neu in Python und die Anleitungen scheinen verschiedene Bibliotheken zu verwenden, um Dinge zu tun. (http.client, httplib und urllib). Kann mir jemand zeigen, wie es geht? Wie können Sie die Standardbibliothek zur Verwendung anweisen?

Tom Squires
quelle
2
Möchten Sie sicherstellen, dass das Zertifikat gültig ist?
Andrew Cox
1
Schauen Sie sich stackoverflow.com/questions/635113/… an . Es scheint genau das abzudecken, wonach Sie suchen.
Geo

Antworten:

120

In Python 3 funktioniert Folgendes. Ich verwende den untergeordneten http.client aus der Standardbibliothek. Weitere Informationen zur Grundautorisierung finden Sie in Abschnitt 2 von rfc2617 . Dieser Code überprüft nicht, ob das Zertifikat gültig ist, stellt jedoch eine https-Verbindung her. Informationen dazu finden Sie in den http.client- Dokumenten.

from http.client import HTTPSConnection
from base64 import b64encode
#This sets up the https connection
c = HTTPSConnection("www.google.com")
#we need to base 64 encode it 
#and then decode it to acsii as python 3 stores it as a byte string
userAndPass = b64encode(b"username:password").decode("ascii")
headers = { 'Authorization' : 'Basic %s' %  userAndPass }
#then connect
c.request('GET', '/', headers=headers)
#get the response back
res = c.getresponse()
# at this point you could check the status etc
# this gets the page text
data = res.read()  
Andrew Cox
quelle
5
In der requestMethodendokumentation [1] wird erwähnt, dass "Strings als" ISO-8859-1 ", der Standardzeichensatz für HTTP, codiert sind. Daher empfehle ich, mit "ISO-8859-1" anstelle von "ASCII" zu dekodieren. [1] docs.python.org/3/library/…
jgomo3
21
Verwenden Sie zum Verwenden von Variablen anstelle von b"username:password": bytes(username + ':' + password, "utf-8").
Kenorb
@ jgomo3: Das .decode("ascii")ist nur für die bytes-> strKonvertierung. Das Ergebnis von b64encodeist sowieso nur ASCII.
Torsten Bronger
1
Mein Retter. Nach 4 Stunden Kampf und einer Ladung Fehlleitung.
Conrad B
Wie verwende ich Standardanmeldeinformationen? Funktioniert dies nicht, wenn ich den Code auf einem anderen System ausführe, oder?
Anandhu
90

Nutzen Sie die Leistungsfähigkeit von Python und stützen Sie sich auf eine der besten Bibliotheken: Anfragen

import requests

r = requests.get('https://my.website.com/rest/path', auth=('myusername', 'mybasicpass'))
print(r.text)

Die Variable r (Anforderungsantwort) enthält viel mehr Parameter, die Sie verwenden können. Am besten gehen Sie in den interaktiven Interpreter und spielen damit herum und / oder lesen Anforderungsdokumente .

ubuntu@hostname:/home/ubuntu$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r = requests.get('https://my.website.com/rest/path', auth=('myusername', 'mybasicpass'))
>>> dir(r)
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'iter_content', 'iter_lines', 'json', 'links', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']
>>> r.content
b'{"battery_status":0,"margin_status":0,"timestamp_status":null,"req_status":0}'
>>> r.text
'{"battery_status":0,"margin_status":0,"timestamp_status":null,"req_status":0}'
>>> r.status_code
200
>>> r.headers
CaseInsensitiveDict({'x-powered-by': 'Express', 'content-length': '77', 'date': 'Fri, 20 May 2016 02:06:18 GMT', 'server': 'nginx/1.6.3', 'connection': 'keep-alive', 'content-type': 'application/json; charset=utf-8'})
IvanD
quelle
22

Update: OP verwendet Python 3. Fügen Sie also ein Beispiel mit httplib2 hinzu

import httplib2

h = httplib2.Http(".cache")

h.add_credentials('name', 'password') # Basic authentication

resp, content = h.request("https://host/path/to/resource", "POST", body="foobar")

Das Folgende funktioniert für Python 2.6:

Ich verwende pycurlviel in der Produktion für einen Prozess, der mehr als 10 Millionen Anfragen pro Tag bearbeitet.

Sie müssen zuerst Folgendes importieren.

import pycurl
import cStringIO
import base64

Ein Teil des grundlegenden Authentifizierungsheaders besteht aus dem Benutzernamen und dem Kennwort, die als Base64 codiert sind.

headers = { 'Authorization' : 'Basic %s' % base64.b64encode("username:password") }

Im HTTP-Header sehen Sie diese Zeile Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=. Die codierte Zeichenfolge ändert sich abhängig von Ihrem Benutzernamen und Passwort.

Wir brauchen jetzt einen Ort, an den wir unsere HTTP-Antwort schreiben können, und ein Curl-Verbindungshandle.

response = cStringIO.StringIO()
conn = pycurl.Curl()

Wir können verschiedene Lockenoptionen einstellen. Eine vollständige Liste der Optionen finden Sie hier . Die verknüpfte Dokumentation bezieht sich auf die libcurl-API, die Optionen ändern sich jedoch nicht für andere Sprachbindungen.

conn.setopt(pycurl.VERBOSE, 1)
conn.setopt(pycurlHTTPHEADER, ["%s: %s" % t for t in headers.items()])

conn.setopt(pycurl.URL, "https://host/path/to/resource")
conn.setopt(pycurl.POST, 1)

Wenn Sie das Zertifikat nicht überprüfen müssen. Warnung: Dies ist unsicher. Ähnlich wie beim Laufen curl -koder curl --insecure.

conn.setopt(pycurl.SSL_VERIFYPEER, False)
conn.setopt(pycurl.SSL_VERIFYHOST, False)

Aufruf cStringIO.writezum Speichern der HTTP-Antwort.

conn.setopt(pycurl.WRITEFUNCTION, response.write)

Wenn Sie eine POST-Anfrage stellen.

post_body = "foobar"
conn.setopt(pycurl.POSTFIELDS, post_body)

Stellen Sie jetzt die eigentliche Anfrage.

conn.perform()

Tun Sie etwas basierend auf dem HTTP-Antwortcode.

http_code = conn.getinfo(pycurl.HTTP_CODE)
if http_code is 200:
   print response.getvalue()
Ocaj Nires
quelle
Das scheint für Pyhthon 2.5 zu sein, ich benutze 3
Tom Squires
Verwenden Sie eine einfache Installation oder Pip? Ist das Pycurl-Paket für Python 3 nicht verfügbar?
Ocaj Nires
Aktualisiert mit einem httplib2. Dies ist verfügbar für Python 3.
Ocaj Nires
Für diejenigen, die neu sind: Im obigen Beispiel fehlt ein Punkt: "pycurl.HTTPHEADER" (Ich würde bearbeiten, aber es ist 1 Zeichen und das Minimum ist 6).
Graeme Wicksted
OP sagte GET, nicht POST
Joe C
16

Es folgt eine korrekte Methode zur grundlegenden Authentifizierung in Python3 urllib.requestmit Zertifikatüberprüfung.

Beachten Sie, dass dies certifinicht obligatorisch ist. Sie können Ihr Betriebssystem-Bundle (wahrscheinlich nur * nix) verwenden oder das CA-Bundle von Mozilla selbst verteilen . Wenn es sich bei den Hosts, mit denen Sie kommunizieren, nur um wenige handelt, verknüpfen Sie die CA-Datei selbst mit den CAs der Hosts, wodurch das Risiko eines MitM- Angriffs durch eine andere beschädigte CA verringert werden kann.

#!/usr/bin/env python3


import urllib.request
import ssl

import certifi


context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(certifi.where())
httpsHandler = urllib.request.HTTPSHandler(context = context)

manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
manager.add_password(None, 'https://domain.com/', 'username', 'password')
authHandler = urllib.request.HTTPBasicAuthHandler(manager)

opener = urllib.request.build_opener(httpsHandler, authHandler)

# Used globally for all urllib.request requests.
# If it doesn't fit your design, use opener directly.
urllib.request.install_opener(opener)

response = urllib.request.urlopen('https://domain.com/some/path')
print(response.read())
saaj
quelle
Das ist toll. Die Überprüfung des Zertifikats ist wichtig, wenn Sie Nur-Text-Anmeldeinformationen (HTTP Basic Auth) senden. Sie müssen dann sicherstellen, dass Ihre TLS-Schicht (HTTPS) sicher ist, da Sie sich darauf verlassen, dass diese Schicht sicher ist.
Four43
Sieht aus korrigieren, aber in meinem Fall hat nicht funktioniert, wird es Fehler wie ssl.SSLCertVerificationError werfen: [SSL: CERTIFICATE_VERIFY_FAILED] Zertifikat fehlgeschlagen verify: unable lokales Aussteller - Zertifikat zu erhalten (_ssl.c: 1056)
neelmeg
Ich habe es herausgefunden, indem ich ein gültiges PEM-Zertifikat an den Verifizierungsparameter und den Cookie-Parameter übergeben habe.
Neelmeg
0

Verwenden Sie nur Standardmodule und keine manuelle Header-Codierung

... was der beabsichtigte und tragbarste Weg zu sein scheint

Das Konzept von Python Urllib besteht darin, die zahlreichen Attribute der Anfrage in verschiedene Manager / Direktoren / Kontexte zu gruppieren ... die dann ihre Teile verarbeiten:

import urllib.request, ssl

# to avoid verifying ssl certificates
httpsHa = urllib.request.HTTPSHandler(context= ssl._create_unverified_context())

# setting up realm+urls+user-password auth
# (top_level_url may be sequence, also the complete url, realm None is default)
top_level_url = 'https://ip:port_or_domain'
# of the std managers, this can send user+passwd in one go,
# not after HTTP req->401 sequence
password_mgr = urllib.request.HTTPPasswordMgrWithPriorAuth()
password_mgr.add_password(None, top_level_url, "user", "password", is_authenticated=True)

handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
# create OpenerDirector
opener = urllib.request.build_opener(handler, httpsHa)

url = top_level_url + '/some_url?some_query...'
response = opener.open(url)

print(response.read())
alexey
quelle
-1

Basierend auf der Antwort von @AndrewCox mit einigen geringfügigen Verbesserungen:

from http.client import HTTPSConnection
from base64 import b64encode


client = HTTPSConnection("www.google.com")
user = "user_name"
password = "password"
headers = {
    "Authorization": "Basic {}".format(
        b64encode(bytes(f"{user}:{password}", "utf-8")).decode("ascii")
    )
}
client.request('GET', '/', headers=headers)
res = client.getresponse()
data = res.read()

Beachten Sie, dass Sie die Codierung festlegen sollten, wenn Sie die bytesFunktion anstelle von verwenden b"".

I159
quelle
-1
requests.get(url, auth=requests.auth.HTTPBasicAuth(username=token, password=''))

Wenn mit Token, sollte das Passwort sein ''.

Für mich geht das.

yidong li
quelle