Appearance
签名代码示例
本文档提供 Java、Node.js、PHP 三种语言的签名与验签完整代码示例。
Java 示例
java
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class SignUtil {
/**
* 计算请求体 SHA256 摘要
*/
public static String sha256Hex(String body) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(body.getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
}
/**
* 构造签名串
*/
public static String buildSignString(String serviceId, String timestamp, String nonceStr, String bodyDigest) {
return serviceId + "\n" + timestamp + "\n" + nonceStr + "\n" + bodyDigest;
}
/**
* 生成 RSA 签名
*/
public static String sign(String serviceId, String timestamp, String nonceStr, String body, String privateKey) throws Exception {
// 1. 计算请求体摘要
String bodyDigest = sha256Hex(body);
// 2. 构造签名串
String signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);
// 3. 生成签名
byte[] keyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey key = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(key);
signature.update(signString.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(signature.sign());
}
/**
* 验证签名
*/
public static boolean verify(String serviceId, String timestamp, String nonceStr, String body, String publicKey, String sign) throws Exception {
// 1. 计算请求体摘要
String bodyDigest = sha256Hex(body);
// 2. 构造签名串
String signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);
// 3. 验证签名
byte[] keyBytes = Base64.getDecoder().decode(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(new java.security.spec.X509EncodedKeySpec(keyBytes));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(key);
signature.update(signString.getBytes("UTF-8"));
return signature.verify(Base64.getDecoder().decode(sign));
}
}Node.js 示例
javascript
const crypto = require('crypto');
/**
* 计算请求体 SHA256 摘要
*/
function sha256Hex(body) {
return crypto.createHash('sha256').update(body).digest('hex');
}
/**
* 构造签名串
*/
function buildSignString(serviceId, timestamp, nonceStr, bodyDigest) {
return `${serviceId}\n${timestamp}\n${nonceStr}\n${bodyDigest}`;
}
/**
* 生成 RSA 签名
*/
function sign(serviceId, timestamp, nonceStr, body, privateKey) {
// 1. 计算请求体摘要
const bodyDigest = sha256Hex(body);
// 2. 构造签名串
const signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);
// 3. 生成签名
return crypto
.createSign('RSA-SHA256')
.update(signString)
.sign(privateKey, 'base64');
}
/**
* 验证签名
*/
function verify(serviceId, timestamp, nonceStr, body, publicKey, sign) {
// 1. 计算请求体摘要
const bodyDigest = sha256Hex(body);
// 2. 构造签名串
const signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);
// 3. 验证签名
return crypto
.createVerify('RSA-SHA256')
.update(signString)
.verify(publicKey, sign, 'base64');
}
// 使用示例
const body = JSON.stringify({
merchant_no: '1234567890',
out_trade_no: '20240101120000',
total_amount: 100
});
const serviceId = 'SVC1234567890';
const timestamp = '1704067200';
const nonceStr = 'abc123def456';
const privateKey = `-----BEGIN PRIVATE KEY-----
Your Private Key Here
-----END PRIVATE KEY-----`;
const signValue = sign(serviceId, timestamp, nonceStr, body, privateKey);
console.log('签名值:', signValue);PHP 示例
php
<?php
class SignUtil {
/**
* 计算请求体 SHA256 摘要
*/
public static function sha256Hex($body) {
return hash('sha256', $body);
}
/**
* 构造签名串
*/
public static function buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest) {
return $serviceId . "\n" . $timestamp . "\n" . $nonceStr . "\n" . $bodyDigest;
}
/**
* 生成 RSA 签名
*/
public static function sign($serviceId, $timestamp, $nonceStr, $body, $privateKey) {
// 1. 计算请求体摘要
$bodyDigest = self::sha256Hex($body);
// 2. 构造签名串
$signString = self::buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest);
// 3. 生成签名
$privateKey = openssl_pkey_get_private($privateKey);
openssl_sign($signString, $sign, $privateKey, OPENSSL_ALGO_SHA256);
return base64_encode($sign);
}
/**
* 验证签名
*/
public static function verify($serviceId, $timestamp, $nonceStr, $body, $publicKey, $sign) {
// 1. 计算请求体摘要
$bodyDigest = self::sha256Hex($body);
// 2. 构造签名串
$signString = self::buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest);
// 3. 验证签名
$publicKey = openssl_pkey_get_public($publicKey);
$result = openssl_verify($signString, base64_decode($sign), $publicKey, OPENSSL_ALGO_SHA256);
return $result === 1;
}
}
// 使用示例
$body = json_encode([
'merchant_no' => '1234567890',
'out_trade_no' => '20240101120000',
'total_amount' => 100
]);
$serviceId = 'SVC1234567890';
$timestamp = '1704067200';
$nonceStr = 'abc123def456';
$privateKey = file_get_contents('private_key.pem');
$signValue = SignUtil::sign($serviceId, $timestamp, $nonceStr, $body, $privateKey);
echo "签名值: " . $signValue . PHP_EOL;