交互示例图

API接出规范流程图

通讯方式

通讯方式HTTPS/HTTP协议
请求报文格式application/json
响应报文格式application/json

请求/响应报文参数列表:


序号参数名参数格式是否必输参数位置参数描述
1KeyidStringYHeaders应用ID,为KY字母开头的字符串,区分大小写
2TimestampStringYHeaders时间戳
3NonceStringYHeaders随机数
4SignatureStringYHeaders签名值
5ciphertextStringYBody(JSON格式传输)加密后的响应内容

请求报文签名规则

开放银行平台向开发者发起的请求,都需要进行签名,以确保是开放银行平台发出的交易指令,签名规则如下:

  • 步骤一:开放银行平台根据 Keyid + "&" + Timestamp + "&" + Nonce + "&" + 业务数据(JSON格式)规则拼接请求报文签名内容,例如:
  • KY0123456789012345678900&20160516120000&025e119557284840a52ec6a404123456&{"amount":"10.00"}     
  • 步骤二:开放银行平台使用平台私钥,以SM3WithSM2算法签名上述字符串,得到的结果(Base64编码)即为签名值,并赋值在http/https报文头Signature字段;
  • 步骤三:开发者收到开放银行平台请求时,需对请求报文解密(解密查看报文加解密算法)后按照步骤一拼接报文,使用开发者响应报文验签公钥对报文请求验签。

响应报文验签规则

开发者响应开放银行平台的请求,需要对响应报文进行签名,签名规则如下:

  • 步骤一:开发者根据 Keyid + "&" + Timestamp + "&" + Nonce + "&" + 业务数据(JSON格式)规则拼接请求报文签名内容,例如:
  • KY0123456789012345678900&20160516120000&025e119557284840a52ec6a404123456&{"amount":"10.00"}   
  • 步骤二:开发者使用请求报文签名私钥,以SM3WithSM2算法签名上述字符串,得到的结果(Base64编码)即为签名值,并赋值在http/https报文头Signature字段。

报文加解密算法

开放银行平台向开发者发送的请求与开发者响应内容采用全报文加密方式请求,加密的后密文采用json格式传输给开发者,参数字段名为:ciphertext。

  • 加密内容为请求报文数据(json格式)明文;
  • 加密算法为:SM4,密码器类型为:SM4/CBC/PKCS5Padding(算法/模式/补码方式),初始向量全部为0。

完整参数示例(Java)

package com.cib.open.callback.vo;

import java.io.Serializable;

/**
 * 回调请求响应实体类
 */
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控制器
 */
@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;
    }
}