兑换系统开放接口


签名生成

<h2>签名生成</h2> <p>商家可以按照下述步骤生成请求的签名。在本节的最后,我们准备了java语言的演示代码供开发者参考。</p> <p>平台要求商家对请求进行签名。平台会在收到请求后进行签名的验证。如果签名验证不通过,平台将会拒绝处理请求。</p> <h3>构造签名串</h3> <ol> <li> <p>将鉴权头部信息(排除<code>sign</code>属性,并忽略空值,如果signType不传值则不加入签名串中)以键值对的方式,按属性名字母升序后用<code>&amp;</code>拼接:</p> <pre><code>businessId=754ea3e3a699404f9b82e8f881107f19&amp;nonce=24bc2c17-0fef-440e-ba32-385c47c6cfa4&amp;signType=MD5&amp;timestamp=1628772138668</code></pre> </li> <li> <p>将请求体转为JSON串(字段不分前后),拼接到步骤1后,生成待签名串:</p> <pre><code class="language-java"> /** * 构建待签名串 * @param headerParams 鉴权头数据(不含sign) * @param dataJson 业务数据的JSON串 * @return 待签名串 */ private String getSignString(Map&lt;String, String&gt; headerParams, String dataJson) { String headerString = headerParams.keySet().stream() .sorted() .map(key -&gt; key + "=" + headerParams.get(key)) .collect(Collectors.joining("&amp;")); return headerString + dataJson; }</code></pre> <p>结果:</p> <pre><code>businessId=754ea3e3a699404f9b82e8f881107f19&amp;nonce=24bc2c17-0fef-440e-ba32-385c47c6cfa4&amp;signType=MD5&amp;timestamp=1628772138668{"businessId":"754ea3e3a699404f9b82e8f881107f19","merchantId":"eb1bb305ca3940f8adf1d4e964555699"}</code></pre> </li> </ol> <h3>计算签名值</h3> <p>把<strong>密钥</strong>追加到待签名串最后,进行<strong>MD5</strong>签名,并对签名结果进行<strong>转换全部大写</strong>得到签名值</p> <pre><code class="language-java"> /** * 数字签名-MD5 * @param content 待签名内容 * @param signKey 签名key * @return 签名串 */ public static String signWithMD5(String content, String signKey) throws Exception { return Md5Utils.digest(String.format("%s%s", content, signKey)).toUpperCase(); }</code></pre> <h3>设置HTTP头</h3> <p>将签名和鉴权头部信息放入HTTP请求头中</p> <h3>演示代码</h3> <pre><code class="language-java"> @Autowired RestTemplate restTemplate; /** * 签名并发送请求 * @param businessId 业务ID * @param signKey 签名key * @param api API接口 * @param data 业务数据 * @param &lt;T&gt; * @return 响应体 */ private &lt;T&gt; ResponseEntity&lt;String&gt; exchangeWithSign(String businessId, String signKey, String api, T data) { // 头部参数 Map&lt;String, String&gt; headerParams = generatorHeaderParams(businessId); // 签名 String dataJson = JSON.toJSONString(data); String signString = getSignString(headerParams, dataJson); log.info("待签名字符串:{}", signString); // 使用商户私钥签名 try { String sign = signWithMD5(signString, signKey); headerParams.put("sign", sign); } catch (Exception e) { e.printStackTrace(); } UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("http://127.0.0.1:8080/") .path(api) .build(true); URI uri = uriComponents.toUri(); // 设置请求头信息 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8")); // 将认证信息加入请求头 headerParams.forEach(headers::add); RequestEntity&lt;String&gt; requestEntity = RequestEntity .post(uri) .headers(headers) .body(dataJson); return restTemplate.exchange(requestEntity, String.class); } /** * 构建鉴权头部数据 * @param businessId * @return */ private Map&lt;String, String&gt; generatorHeaderParams(String businessId) { Map&lt;String, String&gt; headerParams = new HashMap&lt;&gt;(); headerParams.put("businessId", businessId); headerParams.put("nonce", UUID.randomUUID().toString()); headerParams.put("timestamp", String.valueOf(System.currentTimeMillis())); headerParams.put("signType", "MD5"); return headerParams; } /** * 构建待签名串 * @param headerParams 鉴权头数据 * @param dataJson 业务数据的JSON串 * @return 待签名串 */ private String getSignString(Map&lt;String, String&gt; headerParams, String dataJson) { String headerString = headerParams.keySet().stream() .sorted() .map(key -&gt; key + "=" + headerParams.get(key)) .collect(Collectors.joining("&amp;")); return headerString + dataJson; } /** * 数字签名-signWithMD5 * @param content 待签名内容 * @param signKey 签名用的私钥字符串-Base64编码后的 * @return 签名串 * @throws Exception */ public static String signWithMD5(String content, String signKey) throws Exception { return Md5Utils.digest(String.format("%s%s", content, signKey)).toUpperCase(); }</code></pre> <p>Md5Utils:</p> <pre><code class="language-java"> import org.springframework.util.DigestUtils; /** * Md5加密方法 * */ public class Md5Utils { public static String digest(String s) { return DigestUtils.md5DigestAsHex(s.getBytes()); } }</code></pre>

页面列表

ITEM_HTML