有奖捉虫:行业应用 & 管理与支持文档专题 HOT

通讯说明

所有接口均使用 HTTPS 通信,数据包格式为 json(HTTP 请求的 content-type 字段必须使用 application/json)。
请求必须传认证信息,需要传认证码和认证算法。
响应要验证认证码。
所有接口参数名使用的字母均为小写。

数据包格式说明

请求包格式

请求格式示例(以 query_order 接口为例):
{  
    "authen_info": {  
        "a": {  
            "authen_type": 1,  
            "authen_code": "69E65DA0A32F18D059DBE81CA4D9D702470184966E12A03715584249788BD8DD"  
        }  
    },  
    "request_content": "{\\"pay_mch_key\\": {\\"pay_platform\\": 1, \\"sub_pay_platform\\": 100, \\"out_shop_id\\": \\"sz011biKxOguirmBqiFR\\", \\"out_sub_mch_id\\": \\"sz01KzuCUOmw8yjtPite\\", \\"out_mch_id\\": \\"sz01lXKA6DKGjNzr2l4B\\"}, \\"trade_type\\": 1, \\"out_trade_no\\": \\"sz010002cz11564386781\\", \\"nonce_str\\": \\"E94C00688C3F429CA2B0B396BF823548\\", \\"order_client\\": {\\"staff_id\\": \\"1192\\", \\"machine_no\\": \\"1111\\", \\"terminal_type\\": 1, \\"sdk_version\\": \\"1.0\\", \\"device_id\\": \\"12345\\", \\"spbill_create_ip\\": \\"90.0.00.0\\"}}"  
}  
详解: 请求包含两个字段:authen_info 和 request_content。前者表示认证信息,为 json 结构;后者表示请求具体内容,为 json 形式字符串化。
request_content 为具体请求内容的 json 字符串化结构,见各具体接口。
authen_info 结构有嵌套属性 a,字段为认证码:
字段
类型
说明
authen_type
Number(32)
认证算法类型。只支持填1,即为 HMAC-SHA256
authen_code
String(64)
认证码
认证码生成算法:HMAC-SHA256 认证密钥为服务商在云支付录入商户时,在子商户页面上生成的认证密钥。

响应包格式

响应包与请求包类似,包含两个字段:authen_info 和 response_content。前者表示认证信息(响应包仅有认证码方式),为 json 结构;后者表示响应具体内容,为 json 形式字符串化。响应格式示例(以交接班接口为例):
{  
    "authen_info": {  
        "a"{  
           "authen_type": 1,  
            "authen_code" : "1CB622818DF1E2D91741A5FE792F1EFDD2557343FBD1275628E832A95CBB0FBC"  
        }  
    },  
    "response_content": "{\\"status\\":0,\\"description\\":\\"\\\\u64CD\\\\u4F5C\\\\u6210\\\\u529F\\\\u3002\\",\\"log_id\\":1167366844,\\"internal_status\\":0}"  
}  

其它说明

各种 update 接口中,如选填字段不填写,则该字段不需修改。清空此字段时,需上传此字段的内容为空。
接口调用说明 交易接口中的门店信息,必须和子商户在云支付手机端商户管理系统设置的一致。
订单和退款单号说明 为了保护不同商户的订单号不重复,云支付为每个服务商录入的子商户分配“云支付订单前缀”,在云支付后台的商户详情中可以看到,该商户的订单和退款单必须以云支付子商户号做前缀。

数据包构造示例

下面以刷卡支付为例来介绍整个认证过程:

客户端向服务器发送请求

1. 判定使用场景。 在这个示例中,我们要发出的是刷卡支付请求。因此,需要使用认证算法来计算认证码。
2. 根据接口的输入参数,构造 json 格式字符串。


3. 将 json 格式字符串转换为字符串,并使用认证算法,认证 key 来计算认证码。


4. 构造 authen_info 结构。


5. 构造 json 格式的请求数据包,需要包含 authen_info 和 request_content 字段。
6. 将 json 格式请求转换为字符串,发送给服务器。



客户端验证服务器应答消息

1. 将响应包从 string 转换为 json 格式消息。
2. 取出 json 格式消息中的 authen_info 和 response_content 字段信息。
3. 使用认证算法和认证 key 对 response_content 计算认证码。
4. 将计算得到的认证码和 authen_info 中的 authen_code 进行比较;正确情况下,两者应该一致。

代码示例(C++)

构造请求字符串(以刷卡支付为例):
std::string MicroPay_request_str()  
{  
    /* 1.构造业务请求参数 */  
    Json::Value pay_mch_key;      // 构造 pay_mch_key  
    pay_mch_key["pay_platform"]   = 1;  
    pay_mch_key["out_mch_id"]     = "sz013NzuonO6CMJd0rCB";  
    pay_mch_key["out_sub_mch_id"] = "sz01ELTR281OFpmdAp6J";  
    pay_mch_key["out_shop_id"]    = "sz01qyoPJmd3j1hWmul4";  
    Json::Value pay_content;      // 构造 pay_content  
    pay_content["out_trade_no"]   = "sz0100lmnx20171228151031";  
    pay_content["author_code"]    = "134680423163089456";  
    pay_content["total_fee"]      = 1;  
    pay_content["fee_type"]       = "CNY";  
    pay_content["attach"]         = "attach";  
    Json::Value order_client;        // 构造 order_client  
    order_client["machine_no"]       = "32-62-A8-14-B3-C0";  
    order_client["sdk_version"]      = "1.0";  
    order_client["device_id"]        = 1;  
    order_client["spbill_create_ip"] = "192.168.100.75";  
    order_client["staff_id"]         = "1003";  
   order_client["terminal_type"]    = 2;  
    Json::Value request_content;     // 构造 request_content  
    request_content["pay_mch_key"]   = pay_mch_key;  
    request_content["pay_content"]   = pay_content;  
    request_content["order_client"]  = order_client;  
    request_content["nonce_str"]     = "416492026bc84091bcaf7e74ea90ceba";  
    Json::FastWriter w;  
    std::string request_content_str = w.write(request_content);  
    /* 2. 根据上面的业务请求参数计算认证码 */  
    Json::Value authen;  
    std::string hmac;  
   calc_HMAC_SHA256(authen_key, request_content_str, &hmac); //计算认证码  
    authen["authen_code"] = hmac;  
    authen["authen_type"] = 1; //hmac_sha256 为1  
    Json::Value authen_info;  
    authen_info["a"] = authen;  //认证码  
    /* 3. 拼装最终请求参数 */  
    Json::Value request;       //构造最终发给服务器的请求  
    request["request_content"] = request_content_str;  
    request["authen_info"]     = authen_info;  
    std::string request_str = w.write(request);  
    return request_str;  
}  
计算认证码:
/* 
返回是否成功,成功时认证码存放于 hmac 指向的 string 
*/  
bool calc_HMAC_SHA256(const std::string &key, const std::string &input, std::string *hmac)  
{  
    unsigned char md[SHA256_DIGEST_LENGTH] = {0};//32 bytes  
    char format_md[65] = {0};  
    unsigned int md_len = sizeof(md);  
    HMAC_CTX ctx;  
    HMAC_CTX_init(&ctx);  
    if (!HMAC_Init_ex(&ctx, key.data(), (int)key.length(), EVP_sha256(), NULL)  ||  
        !HMAC_Update(&ctx, (const unsigned char *)input.data(), input.length()) ||  
        !HMAC_Final(&ctx, md, &md_len)) {  
        HMAC_CTX_cleanup(&ctx);  
        return false;  
    }  
    HMAC_CTX_cleanup(&ctx);  
    for (int i = 0; i < 32; i++) {  
        snprintf(&format_md[* 2], 3, "%02x", md[i]); //二进制转为十六进制大写  
    }  
    hmac->assign(format_md);  
    // 转大写  
    transform(hmac->begin(), hmac->end(), hmac->begin(), ::toupper);  
    return true;  
}