交互示例图
通讯方式
通讯方式 | HTTPS/HTTP协议 |
请求报文格式 | application/json |
响应报文格式 | application/json |
请求/响应报文参数列表:
序号 | 参数名 | 参数格式 | 是否必输 | 参数位置 | 参数描述 |
---|---|---|---|---|---|
1 | Keyid | String | Y | Headers | 应用ID,为KY字母开头的字符串,区分大小写 |
2 | Timestamp | String | Y | Headers | 时间戳 |
3 | Nonce | String | Y | Headers | 随机数 |
4 | Signature | String | Y | Headers | 签名值 |
5 | ciphertext | String | Y | Body(JSON格式传输) | 加密后的响应内容 |
请求报文签名规则
开放银行平台向开发者发起的请求,都需要进行签名,以确保是开放银行平台发出的交易指令,签名规则如下:
- 步骤一:开放银行平台根据 Keyid + "&" + Timestamp + "&" + Nonce + "&" + 业务数据(JSON格式)规则拼接请求报文签名内容,例如:
KY0123456789012345678900&20160516120000&025e119557284840a52ec6a404123456&{"amount":"10.00"}
响应报文验签规则
开发者响应开放银行平台的请求,需要对响应报文进行签名,签名规则如下:
- 步骤一:开发者根据 Keyid + "&" + Timestamp + "&" + Nonce + "&" + 业务数据(JSON格式)规则拼接请求报文签名内容,例如:
KY0123456789012345678900&20160516120000&025e119557284840a52ec6a404123456&{"amount":"10.00"}
报文加解密算法
开放银行平台向开发者发送的请求与开发者响应内容采用全报文加密方式请求,加密的后密文采用json格式传输给开发者,参数字段名为:ciphertext。
- 加密内容为请求报文数据(json格式)明文;
- 加密算法为:SM4,密码器类型为:SM4/CBC/PKCS5Padding(算法/模式/补码方式),初始向量全部为0。
完整参数示例(Java)
package com.cib.open.callback.vo;
import java.io.Serializable;
/**
* 回调请求响应实体类
*
* @author wenjunxin
* @version 1.0
*/
public class CallBackVO implements Serializable {
private static final long serialVersionUID = -8377720250763137577L;
/**
* 密文
*/
private String ciphertext;
public String getCiphertext() {
return ciphertext;
}
public void setCiphertext(String ciphertext) {
this.ciphertext = ciphertext;
}
}
package com.cib.open.callback.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cib.fintech.dfp.open.sdk.exception.SdkException;
import com.cib.fintech.dfp.open.sdk.util.CallbackUtil;
import com.cib.fintech.dfp.open.sdk.util.SdkUtil;
import com.cib.open.callback.vo.CallBackVO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 回调请求解析demo控制器
*
* @author wenjunxin
* @version 1.0.0
*/
@Controller
public class DemoController {
/**
* 应用私钥,需严格保密,建议使用配置文件或其他方式进行存储
*/
private static final String PRI_KEY = "EalhVM4ZAHm38IYy9Qs/0JTV81r08iEzQG4gJuqYRH8=";
/**
* 响应报文验签公钥
*/
private static final String RESP_PUB_KEY = "BOw5YhsFcvYWXdsMy4BwtFJ9JemdploshmGYeK1Ad3kwj2AQTp35aTAbXhyaXoFjejXmNAusd7enM/u9l5rDc4w=";
/**
* 字段加密密钥
*/
private static final String REQ_PARAM_ENCRYPT_KEY = "uGqeDrX97Azx01+5j9ZhtQ==";
@PostMapping("/callback/demo")
@ResponseBody
public CallBackVO callbackDemo(HttpServletRequest request, HttpServletResponse response, @RequestBody CallBackVO body) {
System.out.println("【>>】接收到回调通知请求: " + JSONObject.toJSONString(body));
// 1.获取请求头信息
String keyId = request.getHeader("Keyid");
String timestamp = request.getHeader("Timestamp");
String nonce = request.getHeader("Nonce");
String signature = request.getHeader("Signature");
// 2.获取请求体内容(加密内容)
String ciphertext = body.getCiphertext();
String reqContent = "";
try {
// 3.对回调请求进行解密验签
reqContent = CallbackUtil.decryptAndVerify(keyId, timestamp, nonce, signature, ciphertext, REQ_PARAM_ENCRYPT_KEY, RESP_PUB_KEY);
} catch (SdkException e) {
e.printStackTrace();
}
// 4.获取请求数据明文,并处理业务数据
// TODO:业务逻辑代码处理---------------------------
// 获取请求内容
JSONObject reqJson = JSON.parseObject(reqContent);
String reqVar1 = reqJson.getString("reqParam1");
System.out.println("reqVar1 = " + reqVar1);
// 生成响应内容
JSONObject respJson = new JSONObject();
respJson.put("respParam1", "respVar1");
respJson.put("respParam2", "respVar2");
// 业务逻辑代码处理结束----------------------------
// 5.业务处理完毕后,对需要返回的业务数据进行签名加密
String signVal = "";
String encryptVal = "";
// 生成时间戳(北京时间)
String respTimestamp = SdkUtil.getDateTime();
try {
signVal = CallbackUtil.signature(keyId, respTimestamp, nonce, respJson.toJSONString(), PRI_KEY);
encryptVal = CallbackUtil.encrypt(respJson.toJSONString(), REQ_PARAM_ENCRYPT_KEY);
System.out.println("【<<】签名加密成功,签名:" + signVal + ", 加密:" + encryptVal);
} catch (SdkException e) {
e.printStackTrace();
}
// 6.封装响应头参数
response.addHeader("Keyid", keyId);
response.addHeader("Timestamp", respTimestamp);
response.addHeader("Nonce", nonce);
response.addHeader("Signature", signVal);
// 将加密信息封装
CallBackVO callBackVO = new CallBackVO();
callBackVO.setCiphertext(encryptVal);
System.out.println("【<<】回调通知消息处理完毕,响应信息:" + JSON.toJSONString(callBackVO));
return callBackVO;
}
}