我在js / php方面不擅长,但我需要将下面的代码转换为Python。
Javascript版本:
function api_query(key,keyId,url,post,body,signature,cb){var method='POST';
var date=new Date();
var content_type='application/x-www-form-urlencoded; charset=UTF-8;';
var body_md5=CryptoJS.MD5(body);
var http= new XMLHttpRequest();http.onreadystatechange=function(){if (http.readyState===4){cb(JSON.parse(http.responseText));}};
http.open("POST",'http://'+url,true);http.setRequestHeader('x-pbx-date',date);
http.setRequestHeader('Accept','application/json');
http.setRequestHeader('Content-Type',content_type);
http.setRequestHeader('Content-MD5',body_md5);
http.setRequestHeader('x-pbx-authentication',keyId+':'+signature);
http.send(body);}
PHP版本:
$post = http_build_query($post);
$content_type = 'application/x-www-form-urlencoded';
$content_md5 = hash('md5', $post);
$signature = base64_encode(hash_hmac('sha1', $method."\n".$content_md5."\n".$content_type."\n".$date."\n".$url."\n", $secret_key, false));
$headers = array('Date: '.$date, 'Accept: application/json', 'Content-Type: '.$content_type, 'x-pbx-authentication: '.$key_id.':'.$signature, 'Content-MD5: '.$content_md5);
if (isset($opt['secure']) && $opt['secure']){
$proto = 'https';
}else{
$proto = 'http';
}
$ch = curl_init($proto.'://'.$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$res = json_decode(curl_exec($ch), true);
if ($res){return $res;}else{return false;}
我试过请求库:
headers = {
'x-pbx-date': date,
'Content-Type': content_type,
'Content-MD5': body_md5_str,
'x-pbx-authentication': signature,
}
payload = {
'date_from': date_from,
'date_to': date_to,
}
r = requests.post(url, data=json.dumps(payload), headers=headers)
httlib2:
http = httplib2.Http()
response, content = http.request(url, 'POST', headers=headers, body=urllib.urlencode(payload))
的urllib2:
req = urllib2.Request(url, data=urllib.urlencode(payload), headers=headers)
response = urllib2.urlopen(req).read()
没有任何作用。在每个尝试服务器响应:未经过身份验证。有任何想法吗?
答案 0 :(得分:1)
嗯,我猜您的问题是身份验证。你没有在Python中展示你是如何做到这一点的,但我想有一些关于它的东西,因为你甚至在你有一个正文(body_md5_str
调用之前)以某种方式计算signature
和json.dumps
,所以一定有些不妥之处。您是否确保您的代码生成与JS和PHP代码相同的值?
就个人而言,我会实现一个身份验证类,它会在请求触发之前添加必要的头文件。有关详细信息,请参阅requests documentation on custom auth,如果我获得了正确的详细信息,请参阅我的(未经测试)尝试:
import requests
import hashlib
import hmac
import base64
from wsgiref.handlers import format_date_time
import datetime
from time import mktime
CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"
class OnlinePBXAuth(requests.auth.AuthBase):
def __init__(self, key_id, secret):
self.key_id = key_id
self.secret = secret
def __call__(self, r):
content_type = r.headers.get("Content-Type", CONTENT_TYPE_FORM_URLENCODED)
body = r.body or ""
body_md5 = hashlib.md5(body).hexdigest()
date = format_date_time(mktime(datetime.datetime.now().timetuple()))
date = r.headers.get("Date", date)
r.headers["Date"] = date
r.headers["X-PBX-Date"] = date
sign = "\n".join([r.method, body_md5, content_type, date, r.url, ""])
signature = base64.b64encode(hmac.new(self.secret, sign, hashlib.sha1).hexdigest())
r.headers["Content-MD5"] = body_md5
r.headers["X-PBX-Authentication"] = "{0}:{1}".format(self.key_id, signature)
return r
不是最漂亮的代码,但我想这应该可以解决问题。
然后,像这样使用它:
auth = OnlinePBXAuth(KEY_ID, KEY_SECRET)
...
data = {"date_from": date_from, "date_to": date_to}
r = requests.post(url, data, auth=auth)
...
或者甚至可能是这样的:
session = requests.Session(auth=OnlinePBXAuth(KEY_ID, KEY_SECRET))
...
r1 = session.post(url, data)
...
r2 = session.post(another_url, another_data)
我不确定它是否适用于空体检查请求(如大多数GET)和多部分块体(因此可以自行计算或者只是试图避免这些),但我认为它应该适用于应用程序/ x-www-form-urlencoded和application / json编码数据。