Python - 使用Oauth2的SSL问题

use*_*601 13 python ssl oauth certificate ssl-certificate

每当尝试在Python中使用oAuth2时,我似乎都遇到了SSL问题.我花了大部分时间试图调试它,但似乎无法搞清楚.

这是我的Python脚本(很简单):

import oauth2.oauth2 as oauth
import urlparse
import time

## If you're actually processing requests, you'll want this
# import simplejson


### GET A REQUEST TOKEN ###

consumer = oauth.Consumer(key="***KEYHERE***", secret="***KEYSECRETHERE***")

request_token_url = 'https://api.instagram.com/oauth/access_token'

client = oauth.Client(consumer)
resp, content = client.request(request_token_url, "GET")

request_token = dict(urlparse.parse_qsl(content))


token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
Run Code Online (Sandbox Code Playgroud)

以及Python解释器中的这些错误:

Traceback (most recent call last):
  File "E:\Projects\oAuth2Test\test.py", line 16, in <module>
    resp, content = client.request(request_token_url, "GET")
  File "E:\Projects\oAuth2Test\oauth2\oauth2.py", line 682, in request
    connection_type=connection_type)
  File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1445, in request
    (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
  File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1197, in _request
    (response, content) = self._conn_request(conn, request_uri, method, body, headers)
  File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1133, in _conn_request
    conn.connect()
  File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 914, in connect
    raise SSLHandshakeError(e)
SSLHandshakeError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Run Code Online (Sandbox Code Playgroud)

现在,就这样知道,我有我的cacerts.txt与httplib2在适当的地方附带,它被发现,但我仍然有这个问题.任何帮助表示赞赏,谢谢!

jfs*_*jfs 8

cacerts.txt包含太少的CA. 如果用cacert.pem替换它,那么就没有ssl错误.这是一个测试脚本:

#!/usr/bin/env python3
import http.client
import ssl

####context = ssl.create_default_context(cafile='cacerts.txt') # ssl.SSLError
####context = ssl.create_default_context(cafile='cacert.pem')  # works   
context = ssl.create_default_context()  # works as is on the recent versions
#NOTE: ssl.CERT_REQUIRED is set for the default Purpose.SERVER_AUTH

h = http.client.HTTPSConnection('api.instagram.com', 443, context=context)
h.request('POST', '/oauth/access_token')
resp = h.getresponse()
print(resp.status, resp.reason) # produce expected 400 http error
print(resp.headers)
print(resp.read())
Run Code Online (Sandbox Code Playgroud)

如示例所示,在最近的软件版本上,默认CA列表可能已足够.


小智 7

首先,跑pip install certifi.然后在发出任何请求之前设置客户端的ca_certs属性:

client = oauth.Client(consumer)
client.ca_certs = certifi.where()
Run Code Online (Sandbox Code Playgroud)

这是受到jterrace建议使用的启发 httplib2.Http.add_certificate