# 统一 API请求参数

# 内容

参数名 是否必填 类型 说明
appId string 商户APP ID,由 Platform 提供
sign string param 的RSA签名
param string 请求参数字符串

# 示例

{
    "appId": "123456",
    "sign": "abcdef",
    "param": "{}"
}

# 说明

  1. appId 是由 Platform 提供的固定值;
  2. 根据具体接口文档,构造请求参数,将请求参数格式化为 JSON 格式,作为 param 的值;
  3. 使用 RSA 私钥对 param 进行签名,得到的值作为 sign 的值。

# 附录 RSA 使用示例(Java 语言)

生成RSA密钥对:

import java.security.*;
import java.util.Base64;

public class RsaGenerateKeyPair {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.genKeyPair();

        PublicKey publicKey = keyPair.getPublic();
        byte[] publicKeyBytes = publicKey.getEncoded();
        String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);
        System.out.println(publicKeyBase64);

        PrivateKey privateKey = keyPair.getPrivate();
        byte[] privateKeyBytes = privateKey.getEncoded();
        String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyBytes);
        System.out.println(privateKeyBase64);
    }
}

RSA 公钥请提交给 Platform,请不要透露给任何第三方。

RSA 私钥由商户保管,请不要透露给任何人。

当商户请求 Platform 的 Open API 时,商户使用 RSA 私钥对请求参数进行签名,Platform 会使用商户提供的 RSA 公钥对请求中的签名进行验证。如果验证失败,Platform 服务器会拒绝处理请求。

# 示例密钥对

RSA 公钥:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8aqn1piRvu6OyAO5shHOsKH/INH73zjwfTZ7A9+cJdLJaHZ+eiuGbM2wUnCTZadpH8xQiNDnBuSAZzByvc+IDCfhFlBGpzpLtBlSS3F2D85yc6HS8CcLVq3lyt5Vs83LU1p/vStaiivdzcFBY3w8X5fnGjU35ybZSgb47ye5s90a6H1tBTf8vzznKMMNj1mqRIGUDBxPy7B4MfrlYT5TmO45aLmrWjh+ng0E6EuU4mMKV4eDvoX+dDDdXmhZ53eDCeyn5V/pMkvpcbVwqXsdF3IbUYAu882DXD/tx2WDFYNmO8JbdJUMbz+6pW9VwGsope5jYfVSLWO0wxqo7kOMQIDAQAB

RSA 私钥:

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/xqqfWmJG+7o7IA7myEc6wof8g0fvfOPB9NnsD35wl0slodn56K4ZszbBScJNlp2kfzFCI0OcG5IBnMHK9z4gMJ+EWUEanOku0GVJLcXYPznJzodLwJwtWreXK3lWzzctTWn+9K1qKK93NwUFjfDxfl+caNTfnJtlKBvjvJ7mz3RrofW0FN/y/POcoww2PWapEgZQMHE/LsHgx+uVhPlOY7jlouataOH6eDQToS5TiYwpXh4O+hf50MN1eaFnnd4MJ7KflX+kyS+lxtXCpex0XchtRgC7zzYNcP+3HZYMVg2Y7wlt0lQxvP7qlb1XAayil7mNh9VItY7TDGqjuQ4xAgMBAAECggEAG4hpPKGcVHaVgSGUIhwE5fHB1kX+0OpMRK9jjhmXXJDMECYRhmiafkQVi2CMjdke3twH9WfcsA/hQWwBAqPGfpacgELULv7yF2+B6ySwL+C76jZFhGGtynEoxIJQVF9Bm7ZujlUQhJo8vs/eX7LGMdWj4m/GiCgSw04j2ulcouRMJPU/FrKnljWI2a8Dy02laTjt5gnulGbd+1V+kxo7BkvpGNAJE1q3Mm6vRDAlEBESOJuv/SRvfKT3L1XvPrIAuVAhmtW4beAXUF7ohWslYWbYy8ct5mWP3457A4COTpTmnV1gcrUTwxiEN9Rjxuxk2zShGLzWJ1DshP+Q++Oh9QKBgQDrRCt6CLIea+pqBEHNeKEBFHfB4FabptZcm17lyk177zDNEAENCsYKsruudotnP5ZkmJk6xl3wcCmsf5UQ3YzWamBxzZZV7CMHf8yUlSeEWf+OvEE05A5oFV2rR2rLvssG4UzuSyEpkFkigblMP7tmCAHhLlLxr2nlAaNXWiV6awKBgQDQrVDFg3OQETQ/HvtBq6REhr6WMqM2CdFTHjDJRFofPr3Vo+tscGN8WNp8cq8Phu1Z9qNn33CF3Zqv/021K92fXMFu1Ha8I3QWxu8aLgUQgWz+cVNTyRNRrgF3Q1V41qN0JAC9kKARL64oT3yZRML53GpbzcEmMyeXC+64sxl40wKBgEhESWKT9zq3BWuJYTkfW718LwkjwxbO2bvakfzd9o0iPQhQaTI7Y/f3TQVbLpkJhEXkRfUy57oqifKNwhlLJK7cQEHU1+AOx/fOvuXJJzlVd9W9Z/46K163aW1qY5iwQ6caX8o207nzuB2MYYHVddfyj7k+xIWuz0VkCmuTqj1/AoGBAMCrpW4YRrT4DYNSOa6SqeLTfljzfBpCylCyCV1rjMJYjbIZ3R6MTm7bIy/QO65cZ/2uaYVYmm4fA9oIIVlrnP6tB7Qq204uddsp5k4Hu4lX1qi/Pa6YcwvxW00gkGQ32Uc8jqp4RDJaEbUKXwKsqFFGn7UProx0otMlo05JnvUdAoGAO1KKSqSWrADfx06uAS8TdBYWV4cVOpfFZiTm3lLD59D3TxlQijXoGdLJsqywdBpe5dhoVMI91i+XDkAOT1xW2yondEdUurnYhijM91OfsoGIJeR30r4DqEDDiuGctgKqi0xWS69i3sFT9w+tANvwSLtQIyU0T70wWb9RhTxafJk=

# RSA 签名:

import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class RsaSign {

    public static final String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/xqqfWmJG+7o7IA7myEc6wof8g0fvfOPB9NnsD35wl0slodn56K4ZszbBScJNlp2kfzFCI0OcG5IBnMHK9z4gMJ+EWUEanOku0GVJLcXYPznJzodLwJwtWreXK3lWzzctTWn+9K1qKK93NwUFjfDxfl+caNTfnJtlKBvjvJ7mz3RrofW0FN/y/POcoww2PWapEgZQMHE/LsHgx+uVhPlOY7jlouataOH6eDQToS5TiYwpXh4O+hf50MN1eaFnnd4MJ7KflX+kyS+lxtXCpex0XchtRgC7zzYNcP+3HZYMVg2Y7wlt0lQxvP7qlb1XAayil7mNh9VItY7TDGqjuQ4xAgMBAAECggEAG4hpPKGcVHaVgSGUIhwE5fHB1kX+0OpMRK9jjhmXXJDMECYRhmiafkQVi2CMjdke3twH9WfcsA/hQWwBAqPGfpacgELULv7yF2+B6ySwL+C76jZFhGGtynEoxIJQVF9Bm7ZujlUQhJo8vs/eX7LGMdWj4m/GiCgSw04j2ulcouRMJPU/FrKnljWI2a8Dy02laTjt5gnulGbd+1V+kxo7BkvpGNAJE1q3Mm6vRDAlEBESOJuv/SRvfKT3L1XvPrIAuVAhmtW4beAXUF7ohWslYWbYy8ct5mWP3457A4COTpTmnV1gcrUTwxiEN9Rjxuxk2zShGLzWJ1DshP+Q++Oh9QKBgQDrRCt6CLIea+pqBEHNeKEBFHfB4FabptZcm17lyk177zDNEAENCsYKsruudotnP5ZkmJk6xl3wcCmsf5UQ3YzWamBxzZZV7CMHf8yUlSeEWf+OvEE05A5oFV2rR2rLvssG4UzuSyEpkFkigblMP7tmCAHhLlLxr2nlAaNXWiV6awKBgQDQrVDFg3OQETQ/HvtBq6REhr6WMqM2CdFTHjDJRFofPr3Vo+tscGN8WNp8cq8Phu1Z9qNn33CF3Zqv/021K92fXMFu1Ha8I3QWxu8aLgUQgWz+cVNTyRNRrgF3Q1V41qN0JAC9kKARL64oT3yZRML53GpbzcEmMyeXC+64sxl40wKBgEhESWKT9zq3BWuJYTkfW718LwkjwxbO2bvakfzd9o0iPQhQaTI7Y/f3TQVbLpkJhEXkRfUy57oqifKNwhlLJK7cQEHU1+AOx/fOvuXJJzlVd9W9Z/46K163aW1qY5iwQ6caX8o207nzuB2MYYHVddfyj7k+xIWuz0VkCmuTqj1/AoGBAMCrpW4YRrT4DYNSOa6SqeLTfljzfBpCylCyCV1rjMJYjbIZ3R6MTm7bIy/QO65cZ/2uaYVYmm4fA9oIIVlrnP6tB7Qq204uddsp5k4Hu4lX1qi/Pa6YcwvxW00gkGQ32Uc8jqp4RDJaEbUKXwKsqFFGn7UProx0otMlo05JnvUdAoGAO1KKSqSWrADfx06uAS8TdBYWV4cVOpfFZiTm3lLD59D3TxlQijXoGdLJsqywdBpe5dhoVMI91i+XDkAOT1xW2yondEdUurnYhijM91OfsoGIJeR30r4DqEDDiuGctgKqi0xWS69i3sFT9w+tANvwSLtQIyU0T70wWb9RhTxafJk=";

    public static void main(String[] args) throws Exception {
        String param = "{\"mchOrderId\":\"Ezpay00001\",\"amount\":5000,\"customerName\":\"EzpayUser\",\"channelCode\":\"PH_GCASH_URL\",\"payMode\":\"WEB\",\"email\":\"Ezpay@gmail.com\",\"redirectUrl\":\"https://www.google.com/\",\"mobile\":\"09123456789\",\"timestamp\":\"1717579821874\"}";

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(PRIVATE_KEY))));
        signature.update(param.getBytes());
        byte[] bytes = signature.sign();
        String sign = Base64.getEncoder().encodeToString(bytes);
        System.out.println(sign);
    }
}

sign 的值:

tFzLYvD0xpevdghs9ukFoStNWBfXY10hHTYOLsLC2AL5H5zjdlF7ALdYAVNuq/aqDJVkqQgDA36maE9BcSpkoYCdtbajrOJ+JADSBO1718LdhTmjzVBU0C4PtUE4XrPHPhI3tfBOUK7aDFEG7RtGLB1gLPzxZRpv8+elc0Tqvt0SooSTyEhaaId20uPAFUIYUF4KDMmiqLpGQ37kHLXglwYa4nix4VbnyEHzw+JzEqSMhrzJAwCw9VIFZxCqOFEJH5yltVDJGlPM5Wm5rP9oHabEM8Qll1LDJZRfaNK/DbQuUT1SJ7hrKRJbD/RR1h5K4c0SjK2T1rHYKavhdSaX5Q==

# RSA 签名验证

import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaVerifySign {

    public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8aqn1piRvu6OyAO5shHOsKH/INH73zjwfTZ7A9+cJdLJaHZ+eiuGbM2wUnCTZadpH8xQiNDnBuSAZzByvc+IDCfhFlBGpzpLtBlSS3F2D85yc6HS8CcLVq3lyt5Vs83LU1p/vStaiivdzcFBY3w8X5fnGjU35ybZSgb47ye5s90a6H1tBTf8vzznKMMNj1mqRIGUDBxPy7B4MfrlYT5TmO45aLmrWjh+ng0E6EuU4mMKV4eDvoX+dDDdXmhZ53eDCeyn5V/pMkvpcbVwqXsdF3IbUYAu882DXD/tx2WDFYNmO8JbdJUMbz+6pW9VwGsope5jYfVSLWO0wxqo7kOMQIDAQAB";

    public static void main(String[] args) throws Exception {
        String param = "{\"mchOrderId\":\"Ezpay00001\",\"amount\":5000,\"customerName\":\"EzpayUser\",\"channelCode\":\"PH_GCASH_URL\",\"payMode\":\"WEB\",\"email\":\"Ezpay@gmail.com\",\"redirectUrl\":\"https://www.google.com/\",\"mobile\":\"09123456789\",\"timestamp\":\"1717579821874\"}";

        String sign = "tFzLYvD0xpevdghs9ukFoStNWBfXY10hHTYOLsLC2AL5H5zjdlF7ALdYAVNuq/aqDJVkqQgDA36maE9BcSpkoYCdtbajrOJ+JADSBO1718LdhTmjzVBU0C4PtUE4XrPHPhI3tfBOUK7aDFEG7RtGLB1gLPzxZRpv8+elc0Tqvt0SooSTyEhaaId20uPAFUIYUF4KDMmiqLpGQ37kHLXglwYa4nix4VbnyEHzw+JzEqSMhrzJAwCw9VIFZxCqOFEJH5yltVDJGlPM5Wm5rP9oHabEM8Qll1LDJZRfaNK/DbQuUT1SJ7hrKRJbD/RR1h5K4c0SjK2T1rHYKavhdSaX5Q==";
                
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(PUBLIC_KEY))));
        signature.update(param.getBytes());
        boolean result = signature.verify(Base64.getDecoder().decode(sign));
        System.out.println(result);
    }
}

result 的值: true