财资云开放平台(开发版)
  1. 开发指南
财资云开放平台(开发版)
  • 接入指南V3
    • 创建应用
    • APIFOX脚本及外部程序使用教程
    • 规则说明
      • 基本原则
      • 错误码
    • 密钥与签名
      • 接口加签方式
      • 签名规则
      • 验签规则
      • 请求内容加密
    • 服务端SDK
      • SDK使用帮助
      • Java
    • 应用开发配置
      • IP白名单
        • 服务器IP白名单
    • 常见问题
  • 接入指南
    • 接口调用方式说明
    • 创建应用
    • APIFOX脚本及外部程序使用教程
    • 应用开发配置
      • 接口加签方式
        • 接口加签方式说明
        • 设置密钥加签方式
        • 开发指南
          • 如何使用密钥
          • 密钥格式说明
          • 自行实现签名
          • 自行实现验签
        • 常见问题
          • 常见问题
        • SAP加签验签指南
      • IP白名单
        • 服务器IP白名单
      • 接口内容加密方式
        • 接口内容加密方式说明
      • 错误码
        • 公共错误码
    • 开发工具包
      • 开发工具包简介
      • 服务端SDK
        • 概述
        • Java
        • PHP
        • .Net
        • Python
        • NodeJS
    • 密钥工具
      • 密钥工具简介
      • 生成密钥
      • 密钥匹配
      • 格式转换
      • 同步验签
      • 签名
      • 异步验签
  • 产品能力
    • 示例产品
      • 示例功能
        • 产品介绍
        • 接入准备
        • 接入指南
        • 常见问题
        • 更新日志
        • API列表
          • API接口列表示例
    • 账户产品
      • 产品介绍
      • 接入准备
      • 接入指南
      • 常见问题
      • 更新日志
      • 账户管理
        • 实体户接口
          • 新增实体账户信息
          • 变更实体账户状态
          • 修改实体账户信息
          • 查询实体账户信息
        • 三方户接口
          • 新增三方户(商户号)信息
          • 变更三方户(商户号)状态
          • 修改三方户(商户号)信息
          • 查询三方户(商户号)信息
        • 内部户接口
          • 新增内部账户信息
          • 变更内部账户状态
          • 修改内部户信息
          • 查询内部账户信息
        • 现金户接口
          • 新增现金户信息
          • 变更现金账户状态
          • 变更现金户信息
          • 查询现金账户信息
        • 虚拟户接口
          • 新增虚拟子账户信息
          • 变更虚拟子账户信息
          • 销户虚拟子账户
          • 查询虚拟子账户信息
      • 账户余额
        • 查询账户余额
        • 同步账户余额(含RPA)--先不处理
      • 账户明细
        • 查询三方账户明细
        • 同步实体账户明细(含RPA)---先不处理
      • 回单(作废)
        • 同步电子回单(含RPA)--先不处理
      • 关联关系(作废)
        • 根据明细查回单
      • 流水
        • 流水
      • 实物资产
        • 实物资产查询接口
      • 合作银行
        • 合作银行查询接口
      • 交易对手
        • 交易对手查询接口
    • 结算产品
      • 应付
        • 产品介绍
        • 接入准备
        • 接入指南
        • 常见问题
        • 更新日志
        • API列表
          • 创建应付款单
          • 应付单查询接口
      • 国内付款
        • 产品介绍
        • 接入准备
        • 接入指南
        • 常见问题
        • 更新日志
        • API列表
          • 创建国内付款
        • 国内支付填写要求
      • 费用报销
        • 产品介绍
        • 接入准备
        • 接入指南
        • 常见问题
        • 更新日志
        • API列表
          • 创建批量报销
      • 工资发放
        • 产品介绍
        • 接入指南
        • 接入准备
        • 常见问题
        • 更新日志
        • API列表
          • 创建工资代发
          • 创建工资批次总额信息
      • 全球付款
        • 产品介绍
        • 接入准备
        • 接入指南
        • 常见问题
        • 更新日志
        • API列表
          • 创建全球付款
      • 撤销付款
        • API列表
          • 撤销付款
      • 付款结果
        • 支付结果通知
        • 支付结果查询
        • 应付结果通知
        • 应付结果查询
      • 单据查询
    • 其他通用产品
      • 系统
        • 组织部门
          • 资源介绍
          • API列表
            • 创建组织部门
            • 修改组织部门
            • 删除组织部门
            • 获取单个组织部门信息
            • 组织部门批量查询
          • 事件列表
            • 组织创建
            • 组织创建
            • 组织变更
            • 删除组织
        • 开户行
          • 开户行查询
        • 系统字典
          • 资源介绍
          • API列表
            • 系统字典查询
            • 银行查询
        • 业务字典
          • 资源介绍
          • API列表
            • 新增业务字典
            • 修改业务字典
            • 重置字典
            • 删除单个业务字典
            • 删除指定类型字典
            • 业务字典批量查询
            • 单个业务字典查询
          • 事件列表
            • 新增业务字典
            • 修改业务字典
            • 删除单个业务字典
            • 删除指定类型字典
            • 重置字典
        • 汇率
          • 新增汇率
          • 修改汇率
          • 删除汇率
          • 查询单条汇率
          • 批量查询汇率
        • 会计科目
          • 新增会计科目
          • 修改会计科目
          • 删除会计科目
          • 查询单个会计科目
          • 批量查询会计科目
        • 交易对手
          • 交易对手信息
        • 通用文件上传
          • 上传文件
    • 票证产品
      • 票据
        • 查询
          • 附件查询
          • 票据正背面查询
        • 操作
          • 签收/承兑 /付款
          • 质押申请
          • 背书申请
          • 贴现申请
          • 撤回操作
          • 撤票操作
          • 提示付款申请
          • 票据同步
          • 票据异常处理
        • 出票申请
        • 票据查询(拆开)
        • 交易状态查询
        • 异步通知(同步 票据当前操作 状态)
        • 票据详情查询
        • 对方是否签收状态查询
      • 新版票据
        • 外部对接
          • 票据贴现对外接口
          • 票据出票对外接口
        • 资产池对接
          • 入池校验/跨行调拨操作
          • 资产池通知操作
      • 信用证
        • 信用证信息查询
        • 【老版本停止维护】信用证信息-推送(全字段版,部分字段改造前暂无)
        • 信用证信息-推送(新版信用证)
      • 贴现运营
        • 查询票据贴现运营列表信息
        • 贴现运营配票进度缓存查询接口
        • 贴现运营-配票接口
    • 对账产品
      • 认领接口
    • 投融资
      • 融资
        • 授信&发行申报
          • 【上报】查询授信&发行申报合同
          • 查询授信合同
          • 授信新增
          • 授信查询
        • 发行申报
          • 查询发行申报
        • 融资合同&内部往来&债券登记
          • 查询融资合同
          • 【上报】查询融资&往来&债券合同
        • 债券登记
          • 查询债券合同
        • 往来借款
          • 内部往来新增
          • 查询往来借款合同
        • 提款&放款
          • 【上报】查询提款&放款列表
        • 贷后
          • 【上报】查询贷后列表
          • 【上报】查询还款记录列表
        • 保函
          • 【上报】查询保函列表
        • 资产台账
          • 【上报】查询资产台账列表
        • 担保
          • 【上报】查询担保列表
        • 融资新增
        • 融资查询
        • 内部往来查询
        • 提款
        • 放款
        • 按期还款
        • 提前还款
      • 投资
        • 存款
          • 存款新增
          • 存款详情查询
          • 存款支取
          • 存款申购
          • 转让
          • 存款结息
          • 存款作废
        • 理财
          • 理财详情查询
          • 理财新增
          • 理财作废
    • 预算和计划
      • API列表
        • 预算控制
      • 资金预算
        • 预算编制查询
        • 预算编制更新接口
    • 身份认证
      • 获取登录预授权码
    • 结算中心
      • 结算中心计息单查询接口
    • 事件中心
      • webhook
        • 明细
          • 实体户明细删除
          • 三方明细删除
        • 对账
          • 应收单
          • 应收单实体账户流水
          • 应收单虚拟户流水
          • 应收单票据流水
          • 实体账户流水票据流水
        • 账户
          • 账户变更销
    • 组织架构
      • 员工
        • 资源介绍
        • API列表
          • 新增员工
          • 员工转用户
          • 修改员工
          • 删除员工信息
          • 查询单个员工信息
          • 批量查询员工信息
        • 事件列表
          • 新增员工
          • 修改员工
          • 删除员工
          • 员工转用户
      • 组织
        • 通过企业名称查询详细信息
        • API列表
          • 通过企业名称查询详细信息
  • 更新日志
    • 产品更新日志
    • 工具更新日志
  • 枚举值
    • 预算跨度
    • 预算颗粒度
    • 滚动颗粒度
    • 滚动期数
    • 参考值取数
    • 预算类型
    • 编制状态
    • 审批状态
    • 编制总状态
    • 催办状态
    • 执行状态
    • 预算旬
    • 预算周
    • 科目分类
    • 收支方向
    • 收支类型
    • 余额模板类型
    • 币种
    • 交易对手种类
    • 账户性质
    • 支付方式
    • 应付来源
  1. 开发指南

自行实现验签

如果未使用财资云开放平台 SDK,需要自行实现验签过程。
此处主要介绍同步返回和异步通知下公钥与证书的验签方法。

同步返回验签#

开发者只对财资云返回的 JSON 中 xxx_response 的值做验签(xxx 代表接口名)。
说明:
• xxx_response 的 JSON 值内容需要包含首尾的 { 和 } 两个尖括号,双引号也需要参与验签。
• 如果字符串中包含 http:// 的正斜杠,需要先将正斜杠做转义,默认打印出来的字符串是已经做过转义的。建议验签不通过时将正斜杠转义一次后再做一次验签。

1. 获取响应值#

如查询员工信息的返回内容为:
{
    "yocyl_basic_employee_querydetail_response": {
        "code": "0",
        "msg": "success",
        "employee": {
            "deptId": "1595233495325913090",
            "workCode": "",
            "name": "张三",
            "sex": 1,
            "birthday": "",
            "age": null,
            "joinedDate": "1980-06-16",
            "workAge": null,
            "idNo": "255255436155",
            "phone": "18682723920",
            "email": "k.fvqte@qq.com",
            "country": "",
            "bank": "XX银行",
            "account": "",
            "bankLocationCode": "XBC",
            "loginName": "老张",
            "isLoginUser": false,
            "outEmployeeId": "1212121",
            "outDeptId": "",
            "sourceSystem": ""
        }
    },
    "sign": "BQWPeP2Rv8q70BPPL+CN8XA3BQg7ekwkvL1U9aXMoe9UfsUKRAkjA/aFFLBrJEWopZX/m+dyEDJCvdtxyEzdOBH/3EF7hhM6Ymb3qudIrsHZp7N2TZSI5LO2ud9P7BYGL6mo5B2gLnnBjAbW66k59iGBGGQrwzyfbwaqgrgmucHaVbITv1WXHIiLkWf7zxCk8iu2qTO5/TZcafgs875OTpw0P3I5HOzTGeMHV/68u29/7YhXxG+oMXiObb+osP4ilx+/QNt/YC//E9ZnFrs7fwRVWGRztNhUU5mGjDxVPGbHpZqT0tD4GgkoZ5McX42I0bQarh4hMAUE0hweYI72tg=="
}

2. 待验签字段#

{
        "code": "0",
        "msg": "success",
        "employee": {
            "deptId": "1595233495325913090",
            "workCode": "",
            "name": "张三",
            "sex": 1,
            "birthday": "",
            "age": null,
            "joinedDate": "1980-06-16",
            "workAge": null,
            "idNo": "255255436155",
            "phone": "18682723920",
            "email": "k.fvqte@qq.com",
            "country": "",
            "bank": "工商银行",
            "account": "",
            "bankLocationCode": "ICBC",
            "loginName": "老张",
            "isLoginUser": false,
            "outEmployeeId": "1212121",
            "outDeptId": "",
            "sourceSystem": ""
        }
    }

3.取出签名值 sign#

BQWPeP2Rv8q70BPPL+CN8XA3BQg7ekwkvL1U9aXMoe9UfsUKRAkjA/aFFLBrJEWopZX/m+dyEDJCvdtxyEzdOBH/3EF7hhM6Ymb3qudIrsHZp7N2TZSI5LO2ud9P7BYGL6mo5B2gLnnBjAbW66k59iGBGGQrwzyfbwaqgrgmucHaVbITv1WXHIiLkWf7zxCk8iu2qTO5/TZcafgs875OTpw0P3I5HOzTGeMHV/68u29/7YhXxG+oMXiObb+osP4ilx+/QNt/YC//E9ZnFrs7fwRVWGRztNhUU5mGjDxVPGbHpZqT0tD4GgkoZ5McX42I0bQarh4hMAUE0hweYI72tg==

4. 调用验签函数#

使用各自语言对应的 SHA256WithRSA (对应 signType 为 RSA2)签名验证函数,传入待验签字段、财资云平台公钥、签名内容(sign),验签方法(signType)进行验签,根据返回结果判定是否验签通过。

异步通知验签#

1. 获取异步通知#

某些情况下(支付成功时),财资云会给企业应用发送异步通知。如果设置的通知地址为 https://api.xx.com/receive_notify, 对应接收到通知的示例如下:
{
    "tenantId": "000001",
    "bizBatchNo": "PV-202305-000061",
    "bizFlowNo": "PV-202305-0000611696552451416538112",
    "bizNoteCode": "PV-202305-000061",
    "bizSystemCode": "XX_XX_GXP",
    "reconcileCode": "S00001",
    "askNumber": "PV-202305-0000611696552451416538112",
    "paySerialNumber": "PV-202305-0000611696552451416538112",
    "payState": 2,
    "payResultMsg": "已支付",
    "bankDealResult": "已支付",
    "payFinishDatetime": "2023-05-30 19:12:00",
    "bankCardNum": "888888",
    "holdName": "XX银行01",
    "source": 1,
    "payBankCode": "CXB",
    "payOrgCode": "01",
    "realPayCurrencyCode": "CNY",
    "realPayAmount": 878888.00,
    "realPayOrgId": 1660522828064256002,
    "payableCurrencyCode": "CNY",
    "payableAmount": 878888.00,
    "payBankLocation": "XX银行股份有限公司XX分行",
    "payBankCnaps": "308100005019",
    "costBearWay": "SHAR",
    "costCurrency": "CNY",
    "recAccountNumber": "666666699999999",
    "recAccountName": "专家",
    "recBankCode": "XBC",
    "recBankName": "中国XX银行",
    "recBankLocation": "中国XX银行XX分行营业管理部",
    "recCnaps": "001110012009",
    "bizScene": 1,
    "createTime": "2023-05-30 19:07:29",
    "signType":"RSA2",
    "payBankSubject": "",
    "bankSerialNumber": null,
    "payResultCode": null,
    "sourceHandlingCode": null,
    "createUserName": null,
    "createUserAccount": null,
    "payableNoteCode": null,
    "otherPayWayInfo": null,
    "collectionId": null,
    "refundDatetime": null,
    "cmbPayLineNumber": null,
    "originalNoteCode": null,
    "bizTypeCode": null,
    "refundExpenditureAccountTransId": null,
    "recSwiftCode": null,
    "payResultNotifyType": null,
    "commission": null,
    "genPacketState": null,
    "sign":"VOxZnKR3v8OaT2q0kq9BIcZ+6gV8+7cX6Y7yS8ickbn6cppZGSAAUkaD4k83IK8fgSWWef9vLrKWOwwd96b3YmBQMrzvZWz4llV8SMoaWrZvR9Z6DAQeJW3TxjDbEDC8lUozb/sFjaR84JovgUFa2mJ+qJpMTuJJpttCE+Qp38emXe5swqlktCwDk9dTHD9LXEL7n+IRhmJU2NwyurZ3bY8Nezr7fCRLDn3MayMj5+xz8OwCw8WF4kSfW0BC/On1ZeM2cO9K6qjV4mFXp0p3Az6cUvFniFBA4Lli8hgHh8PUm2ydW4S5Xm48dIgyL0OUNpjkHdGyFlzikRvXacSl8Q==", 
    "paymentExtension": {
        "actualExchangeRate": null,
        "actualExchangeAmount": null
    }
}

2. 获取待验签参数#

1.
在通知返回参数列表中,除去 sign、signType 两个参数外,凡是通知返回的参数皆是待验签的参数。
2.
将剩下参数进行 urlDecode,然后进行字典排序,组成字符串,得到待签名字符串。

3. 获取签名值 sign#

将签名参数(sign)使用 base64 解码为字节码串。

4. 调用验签函数#

使用 RSA 的验签方法,通过签名字符串、签名参数(经过 base64 解码)及财资云平台公钥验证签名,根据返回结果判定是否验签通过。

示例代码#

import org.apache.commons.codec.binary.Base64;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 验签工具DEMO
 *
 * @author Stewart
 * @version UnsignUtil v1.0 2023/6/2
 */
public class UnsignUtil {

    /**
     * 财资云平台公钥
     */
    private static final String platformPublicKey = "公钥字符串";

    /**
     * 验签方法入口
     *
     * @param requestParam                  请求参数
     * @return                              验签结果
     * @throws Exception                    验签过程中抛出的异常
     */
    private Boolean checkRsa(Map<String, String> requestParam) throws Exception {
        String charset = requestParam.get("charset");
        String sign = requestParam.get("sign");
        String signType = requestParam.get("signType");
        String content = getSignCheckContent(requestParam);
        return doVerify(content, charset, platformPublicKey, sign, signType);
    }

    /**
     * 获取验签内容
     *
     * @param params                        参数
     * @return                              验签参数拼接字符串
     */
    public static String getSignCheckContent(Map<String, String> params) {
        if (params == null) {
            return null;
        } else {
            params.remove("sign");
            StringBuilder content = new StringBuilder();
            List<String> keys = new ArrayList(params.keySet());
            Collections.sort(keys);

            for(int i = 0; i < keys.size(); ++i) {
                String key = keys.get(i);
                String value = params.get(key);
                content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
            }

            return content.toString();
        }
    }

    /**
     * 进行校验
     *
     * @param content                       验签内容
     * @param charset                       字符集
     * @param publicKey                     财资云平台公钥
     * @param sign                          加签字符串
     * @return                              验签结果
     * @throws Exception                    验签过程中发生的异常
     */
    protected static boolean doVerify(String content, String charset, String publicKey, String sign, String signType ) throws Exception {
        PublicKey pubKey = getPublicKey("RSA", publicKey, charset);
        Signature signature = Signature.getInstance(getSignAlgorithm(signType));
        signature.initVerify(pubKey);
        if (hasText(charset)) {
            signature.update(content.getBytes(charset));
        } else {
            signature.update(content.getBytes());
        }

        return signature.verify(Base64.decodeBase64(sign.getBytes(hasText(charset) ?  charset : Charset.defaultCharset().name())));
    }

    /**
     * 获取公钥对象
     *
     * @param algorithm                     加签方式
     * @param publicKey                     财资云平台公钥
     * @param charset                       字符集
     * @return                              公钥对象
     * @throws NoSuchAlgorithmException     算法不存在异常
     * @throws InvalidKeySpecException      密钥不合法异常
     * @throws UnsupportedEncodingException 不支持的字符集异常
     */
    public static PublicKey getPublicKey(String algorithm, String publicKey, String charset) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] encodedKey = Base64.decodeBase64(publicKey.getBytes(charset));
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /**
     * 获取算法名
     *
     * @param signType                      加签类型
     * @return                              算法名
     */
    protected static String getSignAlgorithm(String signType) {
        switch (signType){
            case "RSA2":
                return "SHA256WithRSA";
            case "RSA":
                return "SHA1WithRSA";
            default:
                return null;
        }
    }

    /**
     * 是否有内容
     *
     * @param str                           字符串
     * @return                              是否有内容
     */
    public static boolean hasText(CharSequence str) {
        return isEmpty(str) && containsText(str);
    }

    /**
     * 是否包含内容
     *
     * @param str                           字符串
     * @return                              是否有内容
     */
    private static boolean containsText(CharSequence str) {
        long count = str.chars().filter(chr -> !Character.isWhitespace(chr)).count();
        if(count>0){
            return true;
        }
        return false;
    }

    /**
     * 判断字符串是不是空字符串
     *
     * @param str                           字符串
     * @return                              是否为空
     */
    public static boolean isEmpty(CharSequence str) {
        return str == null || "".contentEquals(str);
    }
}
信息
示例代码中的工具类可自行替换成功能一致的其他工具类。
上一页
自行实现签名
下一页
常见问题
Built with