HikCentral Professional OpenAPI 身份验证和 JSON 数据获取问题

问题描述 投票:0回答:1

我一直在尝试使用 cURL PHP 调用停车费/计算 API,并且我能够获得 200 状态代码,这意味着它到达了服务器。但不知何故,即使我收到 200 状态代码,JSON 数据也没有显示。我得出的结论是这是一个身份验证问题,但我无法真正弄清楚我哪里出了问题。

我已经联系了海康威视的技术支持,但他们在该期限内没有提供帮助,并一直建议我使用 HCP 下载附带的 CSHCSDKDemo 应用程序。看来他们无法理解我的要求。我所附的图片是我收到的错误,它也显示状态代码 200。任何帮助将不胜感激,谢谢。

一开始,我不断收到 HTTP failed request: 400 status code 这样的错误,但是当我更改 headers 参数时,我终于得到了 200 状态码,这意味着成功调用了 API,但附带的 JSON 数据没有显示。而且,在文档中,它提到我需要使用计算签名所以我不确定我哪里出错了。

此 API 的文档链接是:
https://pinfo.hikvision.com/hkwsen/unzip/20240201150721_74009_doc/

API URL 格式为:

https://[serverAddress]:[serverPort]/artemis/api/vehicle/v1/parkingfee/calculate

以下是如何计算签名的说明: 签名计算

  1. 使用appKey或appSecret通过HmacSHA256算法计算签名字符串 生成消息摘要。
  2. 通过BASE64算法计算消息摘要,生成签名。

以下是完整代码:

<?php
$apiUrl = 'https://127.0.0.1:443/artemis/api/vehicle/v1/parkingfee/calculate'; // Replace with actual endpoint
$urlEndpoint = '/api/vehicle/v1/parkingfee/calculate';
$httpMethod = 'POST';
$accept = 'application/json'; 
$acceptEncoding = 'gzip, deflate, sdch';
$acceptLanguage = 'en-US,en;q=0.8';
$connection = 'keep-alive';
$contentType = 'application/json;charset=UTF-8';
$x_requested_with = 'XMLHttpRequest';
$server = '-';
$host = '127.0.0.1';
$transferEncoding = 'chunked';
$x_application_context = '';
$plateLicense = '';
$userAgent = 'Chrome/61.0.3163.100';

$apiKey = '';
$apiSecret = '';

/*******************************************************       CONTENT-MD5         ************************************************************************** */

$requestBody = '';
if(isset($_POST['submitform'])){
    $apiKey = $_POST['apikey'];
    $apiSecret = $_POST['apisecret'];
    $apiUrl = $_POST['apiurl'];
    $requestBody = $_POST['jsonbody'];
}
// $requestBody =  array(
//     'userId' => 'admin',
//     //'plateLicense' => 'UKM9999');
//     'plateLicense' => $plateLicense);
    
$jsonRequestBody = json_encode($requestBody, JSON_UNESCAPED_UNICODE);
$contentMD5 = base64_encode(md5($jsonRequestBody, true));
$contentLength = strlen($requestBody);

/*******************************************************     RESPONSE BODY         ************************************************************************** */
//response body format
$responseBody = array(
    'code' => 0,
    'msg' => 'Success',
    'data' => array(
        'plateLicense' => 'UKM9999',
        'cardNum' => '',
        'parkingInTime' => '2024-06-13T14:22:01+08:00',
        'parkingDuration' => 437809,
        'feeRuleType' => 0,
        'feeRuleIndexCode' => '1',
        'feeRuleName' => 'test rule',
        'fee' => '00.00'));

//encode the above in json format
$jsonResponseBody = json_encode($responseBody, JSON_UNESCAPED_UNICODE);
$jsonDecoded = json_decode($jsonResponseBody, true);
/*******************************************************       UUID/X-CA-NONCE         *********************************************************************** */
function generateUUID() {
    $data = openssl_random_pseudo_bytes(16);
    assert(strlen($data) === 16);

    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // Set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // Set bits 6-7 to 10

    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
$x_ca_nonce = generateUUID();
/*******************************************************        TIMESTAMP         ************************************************************************** */
$dateString = strtotime("Y-M-D h:i:sa"); 
$dateTime = new DateTime($dateString); 
$timestampInSeconds = $dateTime->getTimestamp(); 
$timestampInMilliseconds = $timestampInSeconds * 1000; 
$timestampInMilliseconds2 = round(microtime(true) * 1000);

// Initialize cURL session
$ch = curl_init();

/*******************************************************       SIGNATURE CALCULATION         ***************************************************************** */
$stringToSign = "{$httpMethod}\n". "{$contentMD5}\n". "{$contentType}\n". "{$apiKey}\n". "{$x_ca_nonce}\n". "{$timestampInMilliseconds}\n". "{$urlEndpoint}";

// Generate Signature
$signature = hash_hmac('sha256', $stringToSign, $apiSecret, true);
// Encode Signature (base64)
$base64encodedSignature = base64_encode($signature);
/*******************************************************       CURL SETOPT         ************************************************************************** */

// Set cURL options
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTP_VERSION, 'CURL_HTTP_VERSION_1_1');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_POST, 1); //set request method to post
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Basic YWRtaW46V2VtYWwzMjEh', // Adjust according to API's authentication requirements
    'Accept: '. $accept.'*/*',
    'Accept-Encoding: '. $acceptEncoding,
    'Accept-Language: '. $acceptLanguage,
    'Connection: '. $connection,
    'Content-Length: '. $contentLength, 
    'Content-MD5: '. $contentMD5,
    'Content-Type: '. $contentType,
    'Host: '. $host,
    'Server: '. $server,
    'transferEncoding: '. $transferEncoding, //cant make it like others, will display 400 error again, like Transfer-Encoding
    'X-CA-Key: ' . $apiKey,
    'X-CA-Signature: ' . $base64encodedSignature,
    'X-CA-Signature-Headers: X-CA-Key, X-CA-Timestamp',
    'X-CA-Timestamp: ' . $timestampInMilliseconds,
    'X-CA-Nonce: ' . $x_ca_nonce,
    'userId: admin', 
    'X-Requested-With: '. $x_requested_with
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);

// Execute the request
$response = curl_exec($ch);

// Close the cURL session
curl_close($ch);
?>

<!-- Form Request API -->
<!DOCTYPE html>
<head>
    <title>Test HikVision API</title>
    <style>
        body {
            color:rgb(220, 241, 208);
            background-color: rgb(44, 42, 62);
        }
        .container {
            display: flex;
            justify-content: center;
            align-items: center;
            /*height: 100vh;*/
            margin-top: 100px;
            margin-bottom: 80px;
        }
        .container2 {
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .container3 {
            display: flex;
            justify-content: center;
            /* align-items: center; */
            /*height: 100vh;*/
            margin-top: 50px;
            margin-bottom: 80px;
        }
        .textlarge {
            height: 200px;
            width: 200px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Hikvision Open API Test&emsp;</h1>
        <div class="container2">
            <form name="submitrequest" action="" method="post">
                <label for="APPKey">APP Key: </label><br>
                <input required type="text" name="apikey" placeholder="APP key"><br><br>
                <label for="APPSecret">APP Secret: </label><br>
                <input required type="text" name="apisecret" placeholder="APP secret"><br><br>
                <label for="APIurl">API: </label><br>
                <input required type="text" name="apiurl" placeholder="URL"><br><br>
                <label for="Body">Body: </label><br>
                <input type="text" class="textlarge" name="jsonbody"placeholder="Request Body"><br><br>
                <input type="submit" value="Submit" name="submitform">
            </form>
        </div>
    </div>
    <div class="container3">
        <h1>Results</h1>
    </div>
    <div class="container3">
        <?php
        // Check for errors
        if(isset($_POST['submitform'])){
            if ($response === false) {
                echo 'cURL error: ' . curl_error($ch);
            } else {
                // Decode the JSON response
                $responseData = json_decode($response, false, 512, JSON_UNESCAPED_UNICODE);
                // $responseData = json_decode($response, true);
                // echo $responseData;
                // encoded response
                echo "Encoded response body: " . $response . "<br><br><br>";
                echo "Decoded response body: ";
                if($responseData === NULL) echo "No decoded JSON response. <br><br><br>";
                else echo $responseData . "<br><br><br>"; 
                $resultStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                if ($resultStatus == 200) {
                    // everything went better than expected
                echo "Status Code: ".$resultStatus."<br><br><br>"; 
                print_r($responseData);
                } else {
                    // the request did not complete as expected. common errors are 4xx
                    // (not found, bad request, etc.) and 5xx (usually concerning
                    // errors/exceptions in the remote script execution)
                    die('Request failed: HTTP status code: ' . $resultStatus);
                }
                // Process the response data
                if ($responseData === null && json_last_error() !== JSON_ERROR_NONE) {
                    // echo 'cURL Error: ' . curl_error($ch);
                    echo "Error decoding JSON response: " . json_last_error_msg();
                } elseif ($responseData === null) {
                    echo "The response body is empty!";
                } else {
                    // Everything went as expected
                    echo "HTTP status code: $resultStatus\n";
                    print_r($responseData);
                }
                // print_r($_POST);
                //example if want json to print pretty
                // echo json_encode($this->errors, JSON_PRETTY_PRINT);
            }
        }
        ?>
    </div>
</body>
</html>

我期待它给出这样的 JSON 响应:

{
    "code": "0",
    "msg": "Success",
    "data": {
        "plateLicense": "UKM9999",
        "cardNum": "",
        "parkingInTime": "2024-06-13T14:22:01+08:00",
        "parkingDuration": 2223046,
        "feeRuleType": 0,
        "feeRuleIndexCode": "1",
        "feeRuleName": "test rule",
        "fee": "260.00"
    }
}

我不确定错误是来自签名计算还是头部。但我收到的错误显示:

状态代码:200 解码 JSON 响应时出错:控制字符 错误,可能编码不正确

更新: 我已在这篇文章中附加了一张图片,并编辑了curl 请求并添加了完整的代码。 API调用错误

php json authentication php-curl
1个回答
0
投票

我已经找到了问题的解决方案。首先,我删除了不必要的标头,只保留 Connection、Accept、Content-Type、App Key 和签名作为 CURLOPT_HTTPHEADER 中的标头。然后,我修复了签名计算。我还将文本框中查询的plateLicense 作为数组传递,然后将其编码为 JSON,而不是传递整个 JSON 正文(这也可以工作,但为了测试,我更喜欢将其作为数组传递)。下面的代码是我在 PHP 文件中更改的内容:

//Header
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Connection: '. $connection,
    'Accept: '. $accept,
    'Content-Type: '. $contentType,
    'X-Ca-Key: '. $apiKey,
    'X-Ca-Signature: '. $signature
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonRequestBody);

//Signature calculation
function generateHmacSha256Signature($jsonRequestBody, $apiSecret) {
    return hash_hmac('sha256', $jsonRequestBody, $apiSecret, true);
}

希望这个答案可以帮助遇到同样问题的人!

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.