全局说明
本章节介绍 Thailand Pay 接口的全局交互规范,包括请求方式、签名算法以及签名工具代码示例。
1. 请求方式
| 交互类型 | 请求方法 | Content-Type | 备注 |
|---|---|---|---|
| 订单创建、查询 | POST | application/json; charset=utf-8 | 商户向平台发起的请求 |
| 异步通知回调 | POST | application/json; charset=utf-8 | 平台向商户发送的通知 |
2. 请求头 (Request Headers)
在请求所有接口时,必须在 HTTP Header 中携带以下参数以作身份校验:
| 参数名 | 是否必填 | 类型 | 说明 |
|---|---|---|---|
| merchantNo | 是 | string | 商户号,由平台统一分配提供。 |
| sign | 是 | string | 请求体 JSON 字符串的 RSA-SHA256 签名值(Base64 编码)。 |
3. 签名算法说明
- 构造参数: 按照具体接口的参数定义,构造请求体对象。
- 格式化 JSON: 将请求体参数格式化为标准的 JSON 字符串(注意保持字段结构一致)。
- 加签与验签:
- 商户发送请求: 商户使用自己的 RSA 私钥 对 JSON 请求体进行签名,并将签名结果放入 Header 的
sign字段中。平台会使用商户提供的 RSA 公钥 进行验签。 - 平台回调通知: 平台发送通知时,会使用平台的私钥签名。商户收到后,需要使用 平台公钥 进行验签。
- 商户发送请求: 商户使用自己的 RSA 私钥 对 JSON 请求体进行签名,并将签名结果放入 Header 的
平台测试公钥
IMPORTANT
以下为测试环境的平台公钥,用于验证平台回调的签名(正式环境的公钥将在对接完成后由平台发放):
text
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0kr9IpgDckceWl1g8IRAMV6hALHspEb+SzIsrcc2+Q9WSot/c9YbRZzd+yuzkazMv4HAHeW7oLkG1lcxFYxgPM2x0GbhWqy1Yk5iiARS0h3E2mbuDy7neaL9DzZ411Xwq/pcoEAaklJtwwkXwlIcJGVHUFAebX6Yc6BitcfSvjZe7ilyVX0LA2aTxRGoF490gWo3R7TEXK/Lmdh/rC6FldyexdlAoc1DYbCBFZJQXxJReBbvNj+jJi1BsrsrbrKXBHd9M7/vzBwrHGDa09Y4Yw1wVPm+ZRFFs8hC3bVlZWrpOrR9o9S9kSH47YmnHDPve8fK9/ySEHp6JZ0QxJOnd6DQ0uGdAWswWlIZ4Jjg2qJxC6PHmoRYeWjyc9BuekUtDv9Yiyi9SBfGJQJStjC9PksKsMtUCGaoszPMLhMDGCX9mvYKuxK+vHDK3csWu2iRtX9TIulk/ojNsoZkSKV9tnsmiPFKb9vD79k2RiRyKYVlwpLe9Gyq/joN32i6qIyuN7h5iyms+mxya3DiGNNGdrYwaRGK+nwyJtuZJ9LI8GvWjcq5hVDeAgYnUs16N/ujCbWzHpvzDpmZxgJHXxHPk9TAFzrbTUJQ4p6TBpY87NHb2ozJcOFkFzoYEmqMhivM7vn4gqmd/r1z7PNfjNpJK2dv7pjUQ28S9FEZnsnnJecCAwEAAQ==4. Java 签名工具示例
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SignUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(SignUtil.class);
/**
* 验证签名
*
* @param param 原始 JSON 字符串
* @param sign Base64 签名值
* @param publicKey RSA公钥字符串 (Base64)
* @return 验签是否通过
*/
public static boolean checkSign(String param, String sign, String publicKey) {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))));
signature.update(param.getBytes());
return signature.verify(Base64.getDecoder().decode(sign));
} catch (Exception e) {
LOGGER.error("Sign校验错误 :", e);
}
return false;
}
/**
* 生成签名
*
* @param param 待加签的 JSON 字符串
* @param privateKey RSA私钥字符串 (Base64)
* @return 签名后的 Base64 字符串
*/
public static String sign(String param, String privateKey) {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))));
signature.update(param.getBytes());
byte[] bytes = signature.sign();
return Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
LOGGER.error("Sign签名错误 :", e);
}
return null;
}
}5. 请求发送示例 (Java)
java
Map<String, Object> map = new HashMap<>();
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
map.put("merchantOrderNo", "ORDER_123456789");
// ... 填充其他业务参数
String body = gson.toJson(map);
String sign = SignUtil.sign(body, merchantPrivateKey);
HttpResponse<String> stringHttpResponse = Unirest.post("https://api.thailandpay.com/payin/create")
.header("Content-Type", "application/json; charset=utf-8")
.header("merchantNo", "M1639466186292")
.header("sign", sign)
.body(body)
.asString();6. 商户 RSA 密钥生成示例 (Java)
java
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
public class KeyPairGen {
public static void main(String[] args) throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 公钥
PublicKey publicKey = keyPair.getPublic();
String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
System.out.println("----- Public Key (Provide to Platform) -----");
System.out.println(publicKeyBase64);
// 私钥
PrivateKey privateKey = keyPair.getPrivate();
String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println("----- Private Key (Keep Secret) -----");
System.out.println(privateKeyBase64);
}
}