mitoop / signature-sdk
支持多商户、多应用的 API 请求签名与回调验签。
Requires
- php: ^7.4 || ^8.0
- ext-json: *
- ext-openssl: *
- guzzlehttp/guzzle: ^6.5.0 || ^7.0 || ^8.0
Requires (Dev)
- phpseclib/phpseclib: ^3.0
- phpunit/phpunit: ^9.6 || ^10.5 || ^11.5
Suggests
- phpseclib/phpseclib: Required if you want to use Ed25519Signer for signing and verification.
Provides
None
Conflicts
None
Replaces
None
README
Signature SDK 是框架无关的 PHP 签名库,用来调用 Laravel Signature 保护的 API,并验证平台回调。支持 SHA256-RSA2048、SHA256-HMAC 和 ED25519。
同一个商户可以有多个应用。请求和回调各有一条待签名字符串。
环境要求
- PHP ^7.4 || ^8.0
- ext-openssl
- ext-json
- phpseclib(仅 ED25519)
安装
通过 Composer 安装:
composer require mitoop/signature-sdk
ED25519 需要额外安装:
composer require phpseclib/phpseclib:^3.0
请求签名
商户为每个应用生成一对公私钥,私钥自己保存,公钥放到平台。请求由商户私钥签名,平台用该应用的公钥验签。SHA256-HMAC 没有公私钥,商户和平台共用同一把密钥。
mchid 是商户号,appid 是该商户下的应用号。签名前缀由平台给出,按平台给出的值传入,不能包含连字符。
use Mitoop\SignatureSdk\Client; use Mitoop\SignatureSdk\RequestSigner; use Mitoop\SignatureSdk\Signers\RsaSigner; $signer = new RsaSigner($merchantPrivateKey, $platformPublicKey); $requestSigner = new RequestSigner('10001', 'app_001', $signer, 'your_app'); $client = new Client([ 'base_url' => 'https://api.example.com', ], $requestSigner); $response = $client->post('/api/payments', [ 'order_id' => '123456', 'amount' => 100, ]);
RsaSigner 的第一个参数是商户私钥,用来给请求签名。第二个参数是平台公钥,用来验证回调。HMAC 只需要一把密钥:
use Mitoop\SignatureSdk\Signers\HmacSigner; $signer = new HmacSigner($key);
待签名字符串由请求方法、URI、时间戳、nonce 和实际发出的 JSON 正文组成。每段以 \n 结束,包括最后一段:
POST\n
/api/payments\n
1710000000\n
abc\n
{"order_id":"123456","amount":100}\n
请求方法使用大写。URI 是路径和查询字符串,不包含域名。正文是实际发出的那一份 JSON。
默认校验 TLS 证书,超时 60 秒。需要调整时传入 verify 或 timeout。
回调验签
平台为每个商户的每个应用生成一对公私钥,或一把 HMAC 密钥。平台保存私钥,把对应的公钥交给该应用。商户用这把公钥验证回调。SHA256-HMAC 双方使用同一把密钥。
待签名字符串由时间戳、nonce 和回调正文组成。每段以 \n 结束,包括最后一段:
1710000000\n
abc\n
{"order_id":"123456","status":"success"}\n
平台回调会带上这些请求头,前缀使用平台给出的值:
Your_app-Nonce
Your_app-Signature
Your_app-Signature-Type: YOUR_APP-SHA256-RSA2048
Your_app-Timestamp
取出时间戳、nonce、原始正文和签名后验证:
$verified = $requestSigner->verify($timestamp, $nonce, $body, $signature);
验证通过后返回 HTTP 200,正文恰好为 success。