Python, HTTPS GET với xác thực cơ bản


89

Tôi đang cố gắng thực hiện HTTPS GET với xác thực cơ bản bằng python. Tôi rất mới với python và các hướng dẫn dường như sử dụng các thư viện khác nhau để thực hiện mọi việc. (http.client, httplib và urllib). Bất cứ ai có thể chỉ cho tôi làm thế nào nó được thực hiện? Làm thế nào bạn có thể nói thư viện tiêu chuẩn để sử dụng?


2
Bạn có muốn đảm bảo rằng chứng chỉ là hợp lệ?
Andrew Cox

1
Kiểm tra stackoverflow.com/questions/635113/… . Nó dường như bao gồm chính xác những gì bạn đang tìm kiếm.
Geo

Câu trả lời:


120

Trong Python 3, cách sau sẽ hoạt động. Tôi đang sử dụng http.client cấp thấp hơn từ thư viện chuẩn. Ngoài ra, hãy xem phần 2 của rfc2617 để biết chi tiết về ủy quyền cơ bản. Mã này sẽ không kiểm tra chứng chỉ có hợp lệ không, nhưng sẽ thiết lập kết nối https. Xem tài liệu http.client về cách thực hiện điều đó.

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
Các requesttài liệu hướng dẫn phương pháp [1] lượt đề cập rằng "Strings được mã hóa là 'tiêu chuẩn ISO-8859-1', các charset mặc định cho HTTP". Vì vậy, tôi đề nghị giải mã bằng "ISO-8859-1" thay vì "ASCII". [1] docs.python.org/3/library/...
jgomo3

22
Để sử dụng các biến thay vì b"username:password", sử dụng: bytes(username + ':' + password, "utf-8").
kenorb

1
@ jgomo3: .decode("ascii")Chỉ dành cho chuyển đổi bytes-> str. Kết quả của b64encodedù sao cũng chỉ là ASCII.
Torsten Bronger

1
Vị cứu tinh của tôi. Sau 4 giờ vật lộn và tải hàng loạt hướng.
Conrad B

Làm cách nào để sử dụng thông tin đăng nhập mặc định ?, điều này sẽ không hoạt động nếu tôi chạy mã trong hệ thống khác phải không?
anandhu

91

Sử dụng sức mạnh của Python và dựa trên một trong những thư viện tốt nhất xung quanh: yêu cầu

import requests

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

Biến r (yêu cầu phản hồi) có nhiều tham số hơn mà bạn có thể sử dụng. Điều tốt nhất là vào trình thông dịch tương tác và chơi với nó, và / hoặc đọc tài liệu yêu cầu .

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

Cập nhật: OP sử dụng Python 3. Vì vậy, thêm một ví dụ bằng cách sử dụng 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")

Phần dưới đây hoạt động cho python 2.6:

Tôi sử dụng pycurlrất nhiều trong sản xuất cho một quy trình đạt tới 10 triệu yêu cầu mỗi ngày.

Trước tiên, bạn sẽ cần nhập thông tin sau.

import pycurl
import cStringIO
import base64

Một phần của tiêu đề xác thực cơ bản bao gồm tên người dùng và mật khẩu được mã hóa dưới dạng Base64.

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

Trong tiêu đề HTTP, bạn sẽ thấy dòng này Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=. Chuỗi mã hóa thay đổi tùy thuộc vào tên người dùng và mật khẩu của bạn.

Bây giờ chúng tôi cần một nơi để viết phản hồi HTTP của chúng tôi và một xử lý kết nối curl.

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

Chúng tôi có thể thiết lập các tùy chọn uốn tóc khác nhau. Để có danh sách đầy đủ các tùy chọn, hãy xem phần này . Tài liệu được liên kết dành cho API libcurl, nhưng các tùy chọn không thay đổi đối với các ràng buộc ngôn ngữ khác.

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)

Nếu bạn không cần xác minh chứng chỉ. Cảnh báo: Điều này không an toàn. Tương tự như chạy curl -khoặc curl --insecure.

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

Gọi cStringIO.writeđể lưu trữ phản hồi HTTP.

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

Khi bạn đang thực hiện một yêu cầu ĐĂNG.

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

Thực hiện yêu cầu thực tế ngay bây giờ.

conn.perform()

Làm điều gì đó dựa trên mã phản hồi HTTP.

http_code = conn.getinfo(pycurl.HTTP_CODE)
if http_code is 200:
   print response.getvalue()

Đó có vẻ là cho pyhthon 2,5 im sử dụng 3
Tom Squires

Bạn đang sử dụng cài đặt dễ dàng hay pip? Có phải gói pycurl không khả dụng cho python 3 không?
Ocaj Nires

Cập nhật bằng httplib2. Đây là có sẵn cho python 3.
Ocaj Nires

Đối với những người mới: ví dụ trên thiếu một dấu chấm: "pycurl.HTTPHEADER" (Tôi sẽ chỉnh sửa nhưng đó là 1 ký tự và tối thiểu là 6).
Graeme Wicksted

OP nói GET chứ không phải POST
Joe C

17

Cách chính xác để thực hiện xác thực cơ bản trong Python3 urllib.requestvới xác thực chứng chỉ sau đây.

Lưu ý rằng certifikhông bắt buộc. Bạn có thể sử dụng gói hệ điều hành của mình (chỉ có thể là * nix) hoặc tự phân phối Gói CA của Mozilla . Hoặc nếu các máy chủ mà bạn giao tiếp chỉ là một số ít, hãy tự ghép tệp CA từ các CA của máy chủ, điều này có thể làm giảm nguy cơ tấn công MitM do một CA bị hỏng khác gây ra.

#!/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())

Điều đó thật tuyệt. Xác minh chứng chỉ rất quan trọng khi gửi thông tin xác thực văn bản thuần túy (Xác thực cơ bản HTTP). Khi đó, bạn cần đảm bảo lớp TLS (HTTPS) của mình được bảo mật vì bạn đang dựa vào lớp đó để được bảo mật.
443

Có vẻ đúng, nhưng đã không làm việc trong trường hợp của tôi, nó là ném lỗi như ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] Giấy chứng nhận Kiểm định thất bại: không thể để có được giấy chứng nhận phát hành địa phương (_ssl.c: 1056)
neelmeg

Tôi đã tìm ra nó bằng cách chuyển một chứng chỉ pem hợp lệ đến xác minh param và cookie param.
neelmeg

1

chỉ sử dụng các mô-đun tiêu chuẩn và không có mã hóa tiêu đề thủ công

... có vẻ là cách dự định và dễ di chuyển nhất

khái niệm về python urllib là nhóm nhiều thuộc tính của yêu cầu thành nhiều người quản lý / giám đốc / bối cảnh khác nhau ... sau đó xử lý các phần của chúng:

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

Dựa trên câu trả lời của @AndrewCox với một số cải tiến nhỏ:

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

Lưu ý, bạn nên đặt mã hóa nếu bạn sử dụng byteshàm thay vì b"".


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

Nếu với mã thông báo, mật khẩu phải là ''.

Nó làm việc cho tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.