108 lines
2.7 KiB
PHP
108 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace app\service;
|
|
|
|
/**
|
|
* 签名验证服务
|
|
* 完全按照 Python 版本实现
|
|
*/
|
|
class Signature
|
|
{
|
|
/**
|
|
* 生成API Key
|
|
*/
|
|
public static function generateApiKey()
|
|
{
|
|
return bin2hex(random_bytes(6));
|
|
}
|
|
|
|
/**
|
|
* 生成API Secret
|
|
*/
|
|
public static function generateApiSecret()
|
|
{
|
|
return bin2hex(random_bytes(10));
|
|
}
|
|
|
|
/**
|
|
* 对 API Secret 做 SHA256 哈希存储
|
|
*/
|
|
public static function hashSecret($secret)
|
|
{
|
|
return hash('sha256', $secret);
|
|
}
|
|
|
|
/**
|
|
* 验证签名(完全按照 Python 版本实现)
|
|
*
|
|
* @param array $params 请求查询参数
|
|
* @param string $timestamp X-Timestamp header 值
|
|
* @param string $signature X-Sign header 值
|
|
* @param string $apiSecretHash 数据库存储的 secret 哈希
|
|
* @return bool
|
|
*/
|
|
public static function verify($params, $timestamp, $signature, $apiSecretHash)
|
|
{
|
|
try {
|
|
$ts = (int)$timestamp;
|
|
if ($ts > 1e12) {
|
|
$ts = (int)($ts / 1000);
|
|
}
|
|
$now = time();
|
|
$expireSeconds = env('signature.expire_seconds', 300);
|
|
if (abs($now - $ts) > $expireSeconds) {
|
|
return false;
|
|
}
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
|
|
$sortedParams = [];
|
|
foreach ($params as $k => $v) {
|
|
$sortedParams[$k] = $v;
|
|
}
|
|
ksort($sortedParams);
|
|
|
|
$paramParts = [];
|
|
foreach ($sortedParams as $k => $v) {
|
|
if ($v !== null && $v !== '') {
|
|
$paramParts[] = "{$k}={$v}";
|
|
}
|
|
}
|
|
$paramStr = implode('&', $paramParts);
|
|
$fullStr = $paramStr . '×tamp=' . $timestamp;
|
|
|
|
$expectedSign = hash_hmac('sha256', $fullStr, $apiSecretHash);
|
|
|
|
return strcasecmp($expectedSign, $signature) === 0;
|
|
}
|
|
|
|
/**
|
|
* 生成签名(用于测试)
|
|
*
|
|
* @param array $params 请求参数
|
|
* @param string $timestamp 时间戳字符串
|
|
* @param string $apiSecret API Secret 明文
|
|
* @return string
|
|
*/
|
|
public static function sign($params, $timestamp, $apiSecret)
|
|
{
|
|
$sortedParams = [];
|
|
foreach ($params as $k => $v) {
|
|
$sortedParams[$k] = $v;
|
|
}
|
|
ksort($sortedParams);
|
|
|
|
$paramParts = [];
|
|
foreach ($sortedParams as $k => $v) {
|
|
if ($v !== null && $v !== '') {
|
|
$paramParts[] = "{$k}={$v}";
|
|
}
|
|
}
|
|
$paramStr = implode('&', $paramParts);
|
|
$fullStr = $paramStr . '×tamp=' . $timestamp;
|
|
|
|
return hash_hmac('sha256', $fullStr, $apiSecret);
|
|
}
|
|
}
|