接口说明
简介
此 API 用于提供聚合支付相关的api接口,所有请求均采用 POST 方法,并使用 SHA256withRSA 进行签名认证。
基础 URL
- 基础路径:
https://test-api.fuiouyes.com/
通讯方式
通信采用 HTTP 协议(TLSv1.2), POST 发送 JSON 格式的报文。
请求方式
POST
测试参数
merchantNo:0002270F8017406
shopId: 212628
通用请求参数
合作方系统调用平台 API 接口时,参数需要以通用请求报文格式上送。 上送前,合作方系统需要把业务参数组装成 json 串,赋值到通用请求报文中的 biz_content 字段;然后对通用请求报文进行签名
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| app_id | String | 是 | 平台开发者应用 Id |
| biz_content | Json | 是 | 每个接口的业务参数,需先组装成 json 串 |
| timestamp | String | 是 | Unix 时间戳(秒),10 位数字 |
| nonce_str | String | 是 | 随机字符串,固定 32 位 |
| version | String | 是 | 接口版本号,默认值:1.0 |
| sign_type | String | 是 | 签名类型,默认值:RSA |
| sign | String | 是 | 签名字符串,通过对通用请求报文进行签名得到 |
通用响应参数
合作方系统成功调用 API 接口之后,平台将以通用响应报文格式返回结果数据。 被调用接口的业务数据需要从 data 字段中解析。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | String | 是 | 请求响应码 |
| message | String | 是 | 响应信息 |
| data | Json | 条件 | 业务数据返回值,当 code 为"000000"时必须返回,表示请求成功 |
| sign | String | 是 | 响应签名 |
签名说明
1. 签名机制
采用 RSA 签名保证数据安全。开发者生成密钥对并与开放平台交换公钥,通讯时请求方使用己方私钥签名,响应方使用对方公钥验签。
2. 生成签名密钥
代码生成版:推荐使用命令行方式生成 RSA 公私钥,示例如下:
输入 openssl 进入 OpenSSL>模式 #生成私钥,2048 是密钥长度
OpenSSL> genrsa -out rsa_private_key.pem 2048 #将私钥转换成 PKCS8 格式(C#对应 PKCS1 格式)
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem #根据生成的私钥生成公钥
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem #退出
OpenSSL> exit #在当前目录下可以找到对应的公钥和私钥文件
提示
生成的私钥贵司自行保存好;公钥发到群里,相关同事会给贵司配置参数,方便后续的交易操作。
3. 请求参数加签步骤
(1)步骤:
步骤一:待签名的请求参数,设为数据 D;
步骤二:对请求参数 D,进行参数名 ASCII 码从小到大排序,得到排序后的字符(去前后空格);
步骤三:加签——签名=RSA 签名方法("排序后字符串","自己生成私钥");
步骤四:得到签名后的报文。
请求域名
请联系技术人员获取
签名示例
假设传送的参数如下:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 |
|---|---|---|---|---|
| app_id | 是 | String(32) | 开发者Id | fy20190821aq1tzmv65j |
| version | 是 | String(32) | 版本号,目前固定为1.0 | 1.0 |
| timestamp | 是 | String(32) | Unix时间戳 | 1573428705 |
| nonce_str | 是 | String(32) | 随机字符串 | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
| sign_type | 是 | String(32) | 加密方式 | RSA |
| biz_content | 是 | JSON | 业务参数 | {"merchant_no":"001001F888888"} |
| sign | 是 | String(32) | 签名 |
第一步: 将请求参数中除 sign 外的多个键值对,按照 key=value 的格式,并按照参数名 ASCII 字典序排序如下:
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
// 使用 TreeMap 自动按 key 的 ASCII 字典序排序
Map<String, String> params = new TreeMap<>();
params.put("app_id", "fy20190821aq1tzmv65j");
params.put("biz_content", "{\"merchant_no\":\"001001F888888\"}");
params.put("nonce_str", "5K8264ILTKCH16CQ2502SI8ZNMTM67VS");
params.put("sign_type", "RSA");
params.put("timestamp", "1573428705");
params.put("version", "1.0");
// 拼接成 key=value&key=value 格式
String stringA = params.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
注意
nonce_str 必须参与签名计算。
第二步: 使用私钥进行签名计算
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
// 读取私钥并签名
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKeyObj = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKeyObj);
signature.update(stringA.getBytes("UTF-8"));
byte[] signBytes = signature.sign();
String sign = Base64.getEncoder().encodeToString(signBytes);
第三步: 得到最终发送的数据:
{
"app_id": "fy20190821aq1tzmv65j",
"timestamp": "1573428705",
"nonce_str": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"version": "1.0",
"sign_type": "RSA",
"biz_content": { "merchant_no": "001001F888888" },
"sign": "hASzWUheJyT9q0Ikd+pjdZ+ee4ZG2umKdbY7JSttZs5+64TQTOvHuiGEfdqpFEmwoPUVy2yuwy6+9FzesjWG5lERqogpRtjiHFfznBUYSaDv2GBQIWUMejB0y+3EveNRqIuHbYZvqYXAjpmQc+dSQPBcJwC/X6D53nQfU/uUI3rKujatl6bDyNeVcomhael0nyulh++SY1g9TQPw1deg5VQ1ai2mgs5uGvIrX8grJQbRuNQuf/Dh0TXPvJAoUSqxHIemiC2Hwfo+MOhxlkvNYrnYVW4WvLIl4km7mZqKnVAHVVgN1G9LnqAFgxh1eObqwfz0hw+d79ypjjBJBEAd5Q=="
}
第四步: 发送请求,请求成功,得到响应数据包,开发者需要使用开放平台提供的公钥进行验签。
错误码说明
501002:请求已过期,请检查timestamp501003:重复请求,请更换nonce_str