信托付接口文档
接口规则
支付接口
退款接口
本文档使用 MrDoc 发布
-
+
首页
接口规则
## 协议规则 传输方式:采用HTTP传输(生产环境建议HTTPS) 提交方式:`POST` 或 `GET` 内容类型:`application/json` 字符编码:`UTF-8` 签名算法:`RAS2` ## 参数规范 交易金额:默认为人民币交易,单位为分,参数值不能带小数。 时间参数:所有涉及时间参数均使用精确到毫秒的13位数值,如:1622016572190。时间戳具体是指从格林尼治时间1970年01月01日00时00分00秒起至现在的毫秒数。 ## 签名算法 `签名生成的通用步骤如下` 第一步: 设所有发送或者接收到的数据为集合,提取指定字段`{"mchNo","appId","transferId","refundOrderId","channelOrderNo","mchRefundNo","refundAmount","mchOrderNo","wayCode","amount","notifyUrl","returnUrl","payOrderId","ifCode","state", "version", "payData"}`(不存在的字段跳过) 将提取出来的字段非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。 特别注意以下重要规则: ◆ 参数名ASCII码从小到大排序(字典序); ◆ 如果参数的值为空不参与签名; ◆ 参数名区分大小写; ◆ 验证调用返回或支付中心主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。 ◆ 支付中心接口可能增加字段,验证签名时必须支持增加的扩展字段 第二步: 提取 采用RSA2对stringA进行加签得到sign值signValue 获取签名部分代码如下: ```java public static void main(String[] args) throws Exception { //签名生成 Map<String,Object> params = new HashMap<>(); params.put("mchNo", "M123456789"); params.put("appId", "664970095f763b7c914394e2"); params.put("mchOrderNo", "M0123456789101"); params.put("wayCode","ALI_WAP"); params.put("body","接口调试"); params.put("amount", "10000"); params.put("clientIp", "192.168.0.1"); params.put("subject","接口调试"); params.put("returnUrl", "https://www.baidu.com"); params.put("notifyUrl", "https://www.baidu.com"); params.put("version", "1.0"); params.put("signType","RAS2"); // 待签名字符串 String signStr = getSignStr(params); // 商户私钥 String privateKey = "xxx"; // 商户后台获取的私钥 //获取签名 String sign = sign(signStr,privateKey); } public static String getSignStr(Map<String,Object> map){ String[] signKeys = {"mchNo","appId","transferId", "refundOrderId", "channelOrderNo", "mchRefundNo", "refundAmount","mchOrderNo","wayCode","amount","notifyUrl","returnUrl","payOrderId","ifCode","state", "version", "payData"}; ArrayList<String> list = new ArrayList<String>(); for(Map.Entry<String,Object> entry:map.entrySet()){ if(null != entry.getValue() && !"".equals(entry.getValue()) && Arrays.asList(signKeys).contains(entry.getKey())){ list.add(entry.getKey() + "=" + entry.getValue()); } } int size = list.size(); String [] arrayToSort = list.toArray(new String[size]); Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); StringBuilder sb = new StringBuilder(); for(int i = 0; i < size; i ++) { sb.append(arrayToSort[i]); if (i != size - 1){ sb.append("&"); } } String result = sb.toString(); return result; } /** * 对已加密数据进行签名 * @param data 已加密的数据 * @param privateKey 私钥 * @return 对已加密数据生成的签名 * @throws Exception */ public static String sign(String dataStr, String privateKey) throws Exception { byte[] data = dataStr.getBytes(StandardCharsets.UTF_8); byte[] keyBytes = Base64.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateK); signature.update(data); return Base64.encode(signature.sign()); } ``` 第三步: 将sign加入到请求参数里请求 `最终请求支付系统参数:` ```json https://pay.trust-pay.cn/api/pay/unifiedOrder { "mchNo": "M123456789", "appId": "664970095f763b7c914394e2", "mchOrderNo": "M0123456789101", "wayCode": "ALI_WAP", "body": "接口调试", "clientIp": "192.168.0.1", "amount": 10000, "subject": "接口调试", "returnUrl": "https://www.baidu.com", "notifyUrl": "https://www.baidu.com", "version": "1.0", "signType": "RAS2", "sign": "第二步生成的签名" } ``` ## 验签 支付成功后回调。为了验证是否是支付宝返回的数据,防止在传递过程中被篡改,是为了保证信息的安全性。 ```java public static void main(String[] args) throws Exception { JSONObject params = getReqParamJSON();// 接收到的参数 String sign = params.getSign(); // 提取sign params.remove("sign"); //除去sign // 待签名字符串 String signStr = getSignStr(params); // 平台私钥 String publicKey = "xxx"; // 商户后台获取的平台公钥 //获取签名 if (verify(signStr,publicKey,sign)){ //验签成功 } } /* * 获取待签名字符串 * */ public static String getSignStr(Map<String,Object> map){ String[] signKeys = {"mchNo","appId","transferId", "refundOrderId", "channelOrderNo", "mchRefundNo", "refundAmount","mchOrderNo","wayCode","amount","notifyUrl","returnUrl","payOrderId","ifCode","state", "version", "payData"}; ArrayList<String> list = new ArrayList<String>(); for(Map.Entry<String,Object> entry:map.entrySet()){ if(null != entry.getValue() && !"".equals(entry.getValue()) && Arrays.asList(signKeys).contains(entry.getKey())){ list.add(entry.getKey() + "=" + entry.getValue()); } } int size = list.size(); String [] arrayToSort = list.toArray(new String[size]); Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); StringBuilder sb = new StringBuilder(); for(int i = 0; i < size; i ++) { sb.append(arrayToSort[i]); if (i != size - 1){ sb.append("&"); } } String result = sb.toString(); return result; } /** * 验签 * * @param dataStr 签名之前的数据 * @param publicKey 商户后台里的平台公钥 * @param sign 回调的sign值 * @return 验签是否成功 * @throws Exception */ public static boolean verify(String dataStr, String publicKey, String sign) throws Exception { byte[] data = dataStr.getBytes(StandardCharsets.UTF_8); byte[] keyBytes = Base64.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64.decode(sign)); } ```
admin
2025年2月28日 21:54
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码