我正在尝试按照其官方文档实施身份验证以连接 NIMLAB 加密货币交易所:NIMLAB API 文档。
但是,我不断遇到身份验证和签名生成问题。不幸的是,到目前为止我尝试过的解决方案都不起作用。
NIMLAB 支持团队提供了一个 Python 示例,他们声称该示例完美运行:
import json
import hashlib
import asyncio
import aiohttp
import logging
from aiohttp.client_exceptions import ContentTypeError, ClientConnectorError
from urllib.parse import urlencode, quote
class NIMLABAPI:
def __init__(self, apiUrl, apiKey, apiSecret):
if not apiUrl:
raise ValueError('apiUrl is required in class ExchangerAPI')
if not apiKey:
raise ValueError('apiKey is required in class ExchangerAPI')
if not apiSecret:
raise ValueError('apiSecret is required in class ExchangerAPI')
self.config = {
"apiUrl": apiUrl,
"apikey": apiKey,
"secret": apiSecret
}
self.session = aiohttp.ClientSession()
def generate_hash(self, get_params, post_params):
for key in get_params:
if isinstance(get_params[key], list):
get_params[key] = [str(value) for value in get_params[key]]
else:
get_params[key] = str(get_params[key])
params = {**get_params, **post_params}
checksum_params = hashlib.sha256(json.dumps(params, ensure_ascii=False, separators=(',', ':')).encode()).hexdigest()
HASH = hashlib.sha256((checksum_params + self.config['secret']).encode()).hexdigest()
return HASH
async def call(self, method, param=None, rewriteConfig=None):
if param is None:
param = {}
get = param.get('get', {})
post = param.get('post', {})
post_out = json.dumps(post, ensure_ascii=False)
if not isinstance(get, dict):
return {"errorCode": 20, "message": 'Error invalid "get" params must be object'}
if not isinstance(post, dict):
return {"errorCode": 21, "message": 'Error invalid "post" params must be object'}
configService = {**self.config, **(rewriteConfig or {})}
method_parts = method.split(':')
typeMethod = 'POST'
if len(method_parts) == 2:
typeMethod, method = method_parts[0].upper(), method_parts[1]
else:
method = method_parts[0]
if typeMethod == 'GET':
get['time'] = int(1000 * asyncio.get_event_loop().time())
url_params = "&".join(f"{key}={value}" if not isinstance(value, list) else "&".join(f"{key}[]={item}" for item in value) for key, value in get.items())
url = f"{configService['apiUrl']}{method}?{url_params}" if url_params else f"{configService['apiUrl']}{method}"
HASH = self.generate_hash(get, post)
print(f"URL: {url}")
async with self.session.request(typeMethod, url, headers={
'cache-control': 'no-cache',
'apikey': configService['apikey'],
'hash': HASH,
'Content-Type': 'application/json'
}, data=post_out) as response:
while True:
try:
if response.status in [502, 504, 409]:
logging.warning(f"Error {response.status}: {response.reason}. Retrying in a while...")
await asyncio.sleep(15)
continue
if response.status != 200:
cf_mitigated = response.headers.get('cf-mitigated')
if cf_mitigated:
ray_id = response.headers.get('cf-ray', 'unknown')
raise Exception(f'CloudFlare mitigation required "{cf_mitigated}". RayID: {ray_id}. '
'Ask support to whitelist your IP.')
reason = response.reason or 'Unknown error'
raise Exception(f'Error API: {response.status} - {reason}')
if 'application/json' not in response.headers.get("content-type", ""):
text = await response.text()
raise Exception(f'Error: Response not JSON: {text}')
text = await response.text()
response_data = json.loads(text)
if not response_data.get('success') or not response_data.get('data'):
error_msg = response_data.get('error', 'Unknown error')
raise Exception(f'Error API: {error_msg}')
return json.dumps(response_data.get('data', {}))
except aiohttp.ClientError as error:
logging.exception("API call error", exc_info=error)
async def close(self):
await self.session.close()
我需要使这个逻辑适应 PHP。我已经尝试过使用 hash_hmac 和各种方法来创建签名,但似乎没有任何效果。
任何人都可以帮我将此代码转换为 PHP 或指导我如何通过签名生成正确实现身份验证吗?
API 文档:https://nimlab.eu/service/api-docs/#/
提前谢谢您!
是的,我忘了添加代码:
<?php
class NIMLABAPI {
private $apiUrl;
private $apiKey;
private $apiSecret;
public function __construct($apiUrl, $apiKey, $apiSecret) {
if (empty($apiUrl)) {
throw new InvalidArgumentException('apiUrl is required');
}
if (empty($apiKey)) {
throw new InvalidArgumentException('apiKey is required');
}
if (empty($apiSecret)) {
throw new InvalidArgumentException('apiSecret is required');
}
$this->apiUrl = $apiUrl;
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
}
private function generateHash($getParams, $postParams) {
foreach ($getParams as $key => &$value) {
if (is_array($value)) {
$value = array_map('strval', $value);
} else {
$value = strval($value);
}
}
$params = array_merge($getParams, $postParams);
$checksumParams = hash('sha256', json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$hash = hash('sha256', $checksumParams . $this->apiSecret);
return $hash;
}
public function call($method, $params = [], $rewriteConfig = []) {
$get = $params['get'] ?? [];
$post = $params['post'] ?? [];
if (!is_array($get)) {
return ["errorCode" => 20, "message" => 'Error: "get" params must be an array'];
}
if (!is_array($post)) {
return ["errorCode" => 21, "message" => 'Error: "post" params must be an array'];
}
$configService = array_merge([
'apiUrl' => $this->apiUrl,
'apikey' => $this->apiKey,
'secret' => $this->apiSecret
], $rewriteConfig);
$methodParts = explode(':', $method);
$typeMethod = count($methodParts) === 2 ? strtoupper($methodParts[0]) : 'POST';
$method = count($methodParts) === 2 ? $methodParts[1] : $methodParts[0];
if ($typeMethod === 'GET') {
$get['time'] = intval(microtime(true) * 1000);
}
$urlParams = http_build_query($get);
$url = $configService['apiUrl'] . $method . ($urlParams ? '?' . $urlParams : '');
$hash = $this->generateHash($get, $post);
$headers = [
'cache-control: no-cache',
'apikey: ' . $configService['apikey'],
'hash: ' . $hash,
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $typeMethod);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if ($typeMethod === 'POST') {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post, JSON_UNESCAPED_UNICODE));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
if ($httpCode !== 200) {
$error = "Error: HTTP $httpCode";
if (strpos($contentType, 'application/json') !== false) {
$responseData = json_decode($response, true);
$error = $responseData['error'] ?? $error;
}
curl_close($ch);
throw new Exception($error);
}
curl_close($ch);
$responseData = json_decode($response, true);
if (empty($responseData['success']) || empty($responseData['data'])) {
throw new Exception('API Error: ' . ($responseData['error'] ?? 'Unknown error'));
}
return $responseData['data'];
}
}
?>
尝试使用chatgpt,它总能帮助我解决此类问题!