Python, HTTPS GET с базовой аутентификацией

89

Я пытаюсь выполнить HTTPS GET с базовой аутентификацией с использованием python. Я очень новичок в python, и руководства, похоже, используют разные библиотеки для работы. (http.client, httplib и urllib). Кто-нибудь может показать мне, как это делается? Как вы можете указать использование стандартной библиотеки?

Том Сквайрс
источник
2
Вы хотите убедиться, что сертификат действителен?
Эндрю Кокс,
1
Посетите stackoverflow.com/questions/635113/… . Кажется, это именно то, что вы ищете.
Geo,

Ответы:

120

В Python 3 будет работать следующее. Я использую http.client нижнего уровня из стандартной библиотеки. Также ознакомьтесь с разделом 2 rfc2617 для получения подробной информации о базовой авторизации. Этот код не проверяет действительность сертификата, но установит https-соединение. См. Документацию http.client о том, как это сделать.

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()  
Эндрю Кокс
источник
5
В requestдокументации метода [1] упоминается, что «Строки кодируются как« ISO-8859-1 », кодировка по умолчанию для HTTP». Поэтому я предлагаю декодировать с помощью «ISO-8859-1» вместо «ASCII». [1] docs.python.org/3/library/…
jgomo3
22
Чтобы использовать переменные вместо b"username:password", используйте: bytes(username + ':' + password, "utf-8").
kenorb
1
@ jgomo3: .decode("ascii")только для преобразования bytes-> str. В b64encodeлюбом случае результатом является только ASCII.
Торстен Бронгер
1
Мой спаситель. После 4 часов борьбы и множества неверных направлений.
Conrad B
Как мне использовать учетные данные по умолчанию? Это не сработает, если я запускаю код в другой системе, верно?
anandhu
91

Используйте силу Python и положитесь на одну из лучших библиотек: запросы

import requests

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

Переменная r (запрашивает ответ) имеет гораздо больше параметров, которые вы можете использовать. Лучше всего зайти в интерактивный интерпретатор и поиграть с ним и / или прочитать документы запросов .

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'})
ИванД
источник
23

Обновление: OP использует Python 3. Итак, добавляем пример с использованием httplib2

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

Ниже работает для python 2.6:

Я pycurlмного использую в продакшене для процесса, который выполняет более 10 миллионов запросов в день.

Сначала вам нужно будет импортировать следующее.

import pycurl
import cStringIO
import base64

Часть заголовка базовой аутентификации состоит из имени пользователя и пароля в кодировке Base64.

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

В заголовке HTTP вы увидите эту строку Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=. Закодированная строка меняется в зависимости от вашего имени пользователя и пароля.

Теперь нам нужно место для записи нашего HTTP-ответа и дескриптор соединения curl.

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

Мы можем установить различные варианты завивки. Полный список опций см . Здесь. Связанная документация предназначена для API libcurl, но параметры не меняются для других языковых привязок.

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)

Если вам не нужно проверять сертификат. Предупреждение: это небезопасно. Подобно бегу curl -kили curl --insecure.

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

Вызов cStringIO.writeдля сохранения ответа HTTP.

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

Когда вы делаете запрос POST.

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

Сделайте актуальный запрос сейчас.

conn.perform()

Сделайте что-нибудь на основе кода ответа HTTP.

http_code = conn.getinfo(pycurl.HTTP_CODE)
if http_code is 200:
   print response.getvalue()
Оджай Нирес
источник
Похоже, это для pyhthon 2.5 im с использованием 3
Tom Squires
Вы используете easy install или pip? Пакет pycurl недоступен для python 3?
Ocaj Nires, 09
Обновлено с помощью httplib2. Это доступно для python 3.
Ocaj Nires,
Для новичков: в приведенном выше примере отсутствует точка: "pycurl.HTTPHEADER" (я бы отредактировал, но это 1 символ, а минимум 6).
Graeme Wicksted
OP сказал GET, а не POST
Joe C
17

Далее следует правильный способ выполнить базовую аутентификацию в Python3 urllib.requestс проверкой сертификата.

Обратите внимание, что certifiэто не обязательно. Вы можете использовать свой пакет ОС (вероятно, только * nix) или самостоятельно распространять пакет CA от Mozilla . Или, если хостов, с которыми вы общаетесь, всего несколько, объедините файл CA самостоятельно из центров сертификации хостов, что может снизить риск атаки MitM, вызванной другим поврежденным CA.

#!/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
источник
Это круто. Проверка сертификата важна при отправке учетных данных в виде обычного текста (HTTP Basic Auth). Вам нужно убедиться, что ваш уровень TLS (HTTPS) безопасен, потому что вы полагаетесь на этот уровень в плане безопасности.
four43
Выглядит правильно, но в моем случае не сработало, выдает ошибку, например ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] проверка сертификата не удалась: невозможно получить сертификат локального эмитента (_ssl.c: 1056)
neelmeg
Я понял это, передав действующий сертификат pem параметрам verify и cookies.
neelmeg
1

с использованием только стандартных модулей и без ручного кодирования заголовков

... что кажется предполагаемым и наиболее переносимым способом

концепция urllib python состоит в том, чтобы сгруппировать многочисленные атрибуты запроса в различных менеджеров / директоров / контекстов ... которые затем обрабатывают свои части:

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())
Алексей
источник
0

На основе ответа @AndrewCox с некоторыми незначительными улучшениями:

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

Обратите внимание: вы должны установить кодировку, если используете bytes функцию вместо b"".

I159
источник
-1
requests.get(url, auth=requests.auth.HTTPBasicAuth(username=token, password=''))

Если с токеном, пароль должен быть '' .

Меня устраивает.

Идун Ли
источник