我最近从flask
+ requests
转到aiohttp
及其异步http客户端。
在我的场景中,我需要通过HTTPS
(使用自定义证书)调用API并发送客户端证书。
对于第一部分(验证自定义证书),支持是明确的clearly documented int the docs,并且效果很好。
另一方面,对于第二部分,我似乎无法找到一种简单的方法来附加自定义SSL客户端证书来授权客户端。
你们知道怎么做吗?非常感谢!
答案 0 :(得分:12)
编辑:我已经提交了PR,其中包含有关该主题的aiohttp文档的更新,并已合并。
对于将来可能遇到此问题的任何人。
<强> TL:DR 强>
import ssl
import aiohttp
ssl_ctx = ssl.create_default_context(cafile='/path_to_client_root_ca')
ssl_ctx.load_cert_chain('/path_to_client_public_key.pem', '/path_to_client_private_key.pem')
conn = aiohttp.TCPConnector(ssl_context=ssl_ctx)
session = aiohttp.ClientSession(connector=conn)
# session will now send client certificates..
长篇大论 - 我已经了解了它是如何在请求中实现的(它整齐地记录了API here),显然它是在 urllib3 <内部实现的/强>
urllib3将cert
参数一直向下移动到其HTTPSConnection对象,最终调用此函数:
...
self.sock = ssl_wrap_socket(
sock=conn,
keyfile=self.key_file,
certfile=self.cert_file,
ssl_context=self.ssl_context,
)
...
确实:
...
if ca_certs or ca_cert_dir:
try:
context.load_verify_locations(ca_certs, ca_cert_dir)
except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2
raise SSLError(e)
# Py33 raises FileNotFoundError which subclasses OSError
# These are not equivalent unless we check the errno attribute
except OSError as e: # Platform-specific: Python 3.3 and beyond
if e.errno == errno.ENOENT:
raise SSLError(e)
raise
elif getattr(context, 'load_default_certs', None) is not None:
# try to load OS default certs; works well on Windows (require Python3.4+)
context.load_default_certs()
if certfile:
context.load_cert_chain(certfile, keyfile)
if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI
return context.wrap_socket(sock, server_hostname=server_hostname)
...
这里有趣的调用是load_cert_chain
- 这意味着如果我们只是创建一个ssl.SSLContext
(这是一个标准的库接口)对象,并使用我们的客户端证书调用load_cert_chain
,aiohttp的行为与requests \ urllib3相同。
因此,虽然aiohttp的文档缺乏告诉您的内容,但他们确实指定您可以加载自己的ssl.SSLContext
。