Python,具有基本身份验证的HTTPS GET


89

我正在尝试使用python使用基本身份验证进行HTTPS GET。我对python非常陌生,这些指南似乎使用不同的库来做事。(http.client,httplib和urllib)。谁能告诉我它是如何完成的?您如何告诉标准库使用?


2
您要确保证书有效吗?
安德鲁·考克斯

1
查看stackoverflow.com/questions/635113/…。它似乎完全涵盖了您要查找的内容。
地理

Answers:


120

在Python 3中,以下将起作用。我正在使用标准库中较低级别的http.client。另请参阅rfc2617的第2以了解基本授权的详细信息。此代码不会检查证书是否有效,但会建立一个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 2015年

1
@ jgomo3:.decode("ascii")仅用于bytes->str转换。b64encode无论如何,结果为仅ASCII。
Torsten Bronger

1
我的救星。经过4小时的奋斗和方向错误的负载。
康拉德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使用Python3。因此使用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每天在生产过程中大量资源,每天要处理超过1000万个请求。

您首先需要导入以下内容。

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

我们可以设置各种卷曲选项。有关选项的完整列表,请参见this。链接的文档适用于libcurl API,但是对于其他语言绑定,该选项不会更改。

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

这似乎适用于使用3的pyhthon 2.5 im
Tom Squires

您使用的是简易安装还是pip?pycurl软件包对python 3不可用吗?
Ocaj Nires 2011年

使用httplib2更新。这对于Python 3
Ocaj Nires

对于那些是新手:上面的示例缺少点:“ pycurl.HTTPHEADER”(我将进行编辑,但它是1个字符,最小为6个字符)。
Graeme Wicksted 2014年

OP说是GET,而不是POST
Joe C

17

下面是使用证书验证在Python3中进行基本身份验证的正确方法urllib.request

请注意,这certifi不是强制性的。您可以使用OS捆绑软件(可能仅* nix),也可以自己分发Mozilla的CA捆绑软件。或者,如果您要与之通信的主机只有少数几个,则将自己的CA文件与主机的CA连接起来,这样可以减少由另一个损坏的CA引起的MitM攻击的风险。

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

这很棒。发送纯文本凭据(HTTP基本身份验证)时,证书验证很重要。然后,您需要确保TLS层(HTTPS)是安全的,因为您依赖该层是安全的。
four43

看起来正确,但在我的情况下不起作用,它抛出诸如ssl.SSLCertVerificationError之类的错误:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败:无法获取本地发行者证书(_ssl.c:1056)
neelmeg

我通过将有效的pem证书传递给verify参数和cookie参数来解决这个问题。
neelmeg

1

仅使用标准模块,不使用手动标头编码

...这似乎是预期的且最可移植的方式

python urllib的概念是将请求的众多属性分为不同的管理器/导演/上下文...然后处理它们的部分:

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

请注意,如果您使用bytesfunction而不是,则应该设置编码b""


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

如果使用令牌,则密码应为''

这个对我有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.