如何使用信任库通过requests模块进行身份验证?
我现在正在为我写的编译器编写一个Python语言的插件,这个编译器可以自动进行HTTP调用,主要是为了一个RESTful API。我已经成功地使用socket和ssl模块实现了登录和身份验证,但这种低级的方法在解析响应以获取身份验证令牌和密钥时似乎会出现一些潜在问题。requests模块看起来很流行也很高效,但我似乎无法让它正常工作以满足我的特定身份验证需求。我使用的是一个.pem格式的信任存储文件(里面只有一个公钥),这个文件是我从用于Java插件的.jks文件转换过来的。服务器希望在请求体中以json格式提交用户名和密码。以下是我尝试使用的代码:
#Server and login data
...
host = 'localhost'
port = 8443
pem_file = "C:\\Users\\aharasta\\pycert.pem"
#Digest password with MD5 algorithm
m = hashlib.md5()
m.update(password)
encrypted_password = m.hexdigest()
url = <url>
data = {'userid': user_name, 'password': encrypted_password}
json_data = json.dumps(data)
headers = {'Content-type': 'application/json', 'Accept': 'text/plain', 'Content \
Length': len(json_data)}
r = requests.post(url, headers = headers, data = json_data, cert = pem_file)
print(r)
执行这段代码时,会出现一个SSL错误,提示“证书验证失败”。如果我添加参数verify = False
或verify = pem_file
,服务器会返回404响应。我还要提到的是,当我以调试模式启动服务器并执行请求(使用其中一个验证参数)时,请求根本没有到达服务器的身份验证方法,或者说根本没有到达任何方法。对此问题的任何见解或帮助将非常感谢!
1 个回答
首先,你发的内容有几个问题:
你提到了
host
和port
,但没有给出具体的url
示例,所以我们只能猜测你是在本地测试,并且可以看到发送到服务器的请求。我不太清楚你说的是什么方法,但如果你在用类似 Flask 的东西来开发服务器,你可能不想把认证信息作为 JSON 数据发送。使用认证头是有原因的,requests 也有处理认证的工具。;-)你不应该自己指定
Content-Length
这个头。requests 会为你处理这个。更重要的是,你指定得不正确(根据你发的内容),所以 404 错误可能是因为服务器收到了一个它不认识的头。
现在,没必要指定 verify=False
,你可以指定 cert=pem_file
或者 verify=pem_file
。这两种方式都可以,但绝对不要用 verify=False
。
最后,抛出的 SSLError
是在告诉你,你提供的 pem
文件和服务器要求的不匹配。考虑到这一点,你可能需要检查一下本地服务器的设置。requests 本身并不处理证书验证,但 urllib3 会处理。我们只是根据你提供的参数来设置它。我怀疑这不是 urllib3 的问题,因为它抛出的 SSLError
是来自标准库的 ssl
模块。
编辑
解释在于 文档中,指定 *.pem
文件作为 cert
是无效的。你必须使用 verify='/path/to/file.pem'
来正确处理。
编辑 #2
要检查已经发送的请求,你可以这样做:
r = requests.post(...)
r.request
# PreparedRequest('POST', url, ...)
r.request.body
r.request.headers
# etc.
要在发送之前修改请求,你可以这样做:
from requests import Request, Session
s = Session()
r = Request('POST', url, datajson_data, headers=headers)
p = r.prepare()
p.body = 'New body'
p.headers = #etc.
s.send(p, verify=pem_file)