服务端接入文档
<p>[TOC]</p>
<h2>通用说明</h2>
<h3>接口协议说明</h3>
<p>接口数据请求不采用 json 格式封装的字符串,直接采用post 的 application/x-www-form-urlencoded 方式提交请求。响应返回均为 json 格式。</p>
<table>
<thead>
<tr>
<th style="text-align: left;">名称</th>
<th style="text-align: left;">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">说明</td>
<td style="text-align: left;">服务端接口说明</td>
</tr>
<tr>
<td style="text-align: left;">协议</td>
<td style="text-align: left;">HTTPS</td>
</tr>
<tr>
<td style="text-align: left;">请求方式</td>
<td style="text-align: left;">POST</td>
</tr>
<tr>
<td style="text-align: left;">编码格式</td>
<td style="text-align: left;">UTF8</td>
</tr>
<tr>
<td style="text-align: left;">请求内容类型</td>
<td style="text-align: left;">application/x-www-form-urlencoded</td>
</tr>
<tr>
<td style="text-align: left;">响应内容类型</td>
<td style="text-align: left;">application/json</td>
</tr>
</tbody>
</table>
<h3>API请求结构</h3>
<table>
<thead>
<tr>
<th style="text-align: left;">名称</th>
<th style="text-align: left;">描述</th>
<th style="text-align: left;">备注</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">公共参数</td>
<td style="text-align: left;">每个接口都包含的通用参数</td>
<td style="text-align: left;">详见 <strong>公共请求参数</strong> 说明</td>
</tr>
<tr>
<td style="text-align: left;">私有参数</td>
<td style="text-align: left;">每个接口特有的参数</td>
<td style="text-align: left;">详见每个API接口定义</td>
</tr>
</tbody>
</table>
<h2>公共请求参数</h2>
<p>在进行API请求时,需要传递的一系列共同的参数。</p>
<table>
<thead>
<tr>
<th style="text-align: left;">参数名称</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">是否必选</th>
<th style="text-align: left;">最大长度</th>
<th style="text-align: left;">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">appId</td>
<td style="text-align: left;">String</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">9</td>
<td style="text-align: left;">应用标识,在商户管理平台创建产品时统一分配,应用标识。</td>
</tr>
<tr>
<td style="text-align: left;">ver</td>
<td style="text-align: left;">String</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">2</td>
<td style="text-align: left;">接口版本号 详见 <strong>版本号参数</strong> 说明</td>
</tr>
<tr>
<td style="text-align: left;">timestamp</td>
<td style="text-align: left;">Number</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">13</td>
<td style="text-align: left;">请求当前 UNIX 时间戳(毫秒单位)</td>
</tr>
<tr>
<td style="text-align: left;">nonce</td>
<td style="text-align: left;">String</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">32</td>
<td style="text-align: left;">随机字符串与timestamp 联合起来</td>
</tr>
<tr>
<td style="text-align: left;">sign</td>
<td style="text-align: left;">String</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">32</td>
<td style="text-align: left;">签名,详见 <strong>签名工具类</strong>。所有请求参数(包括公共参数和私有参数,但不包括 sign 参数)。 <strong>1> </strong>按照参数名ASCII码表升序顺序排序 如:foo=1, bar=2, foobar=3, baz=4 排序后的顺序是 bar=2, baz=4, foo=1, foobar=3 将排序好的参数名和参数值构造成字符串,格式为:key1+value1+key2+value2…根据上面的示例得到的构造结果为:bar2baz4foo1foobar3 <strong>2> </strong>选择与 appid 配对的 appkey ,加到上一步构造好的参数字符串之后,如 appKey=6308afb129ea00301bd7c79621d07591则最后的参数字符串为 bar2baz4foo1foobar36308afb129ea00301bd7c79621d07591 <strong>3> </strong>把拼装好的字符串采用 utf-8 编码,使用 SM3 算法对字符串进行摘要,计算得到 sign 参数值,将其加入到接口请求参数中即可。</td>
</tr>
</tbody>
</table>
<h2>API接口</h2>
<h3>获取会话密钥解密uToken</h3>
<p><strong>请求URL:</strong></p>
<ul>
<li><code>https://mr.jjdaq.com/mirenServer/{ver}/app/getRiskControlKey</code></li>
</ul>
<p><strong>请求方式:</strong></p>
<ul>
<li>POST</li>
</ul>
<p><strong>参数:</strong></p>
<table>
<thead>
<tr>
<th style="text-align: left;">参数名称</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">是否必选</th>
<th style="text-align: left;">最大长度</th>
<th style="text-align: left;">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">digest</td>
<td style="text-align: left;">string</td>
<td style="text-align: left;">必填</td>
<td style="text-align: left;">96</td>
<td style="text-align: left;">签名摘要(SDK无感登录接口返回的签名值)</td>
</tr>
</tbody>
</table>
<p><strong>返回示例</strong></p>
<pre><code>{
&quot;msg&quot;: &quot;描述&quot;,
&quot;code&quot;: 状态码,
&quot;data&quot;: &quot;{\&quot;sessionKey\&quot;:\&quot;base64编码后的会话密钥\&quot;}&quot;
}
</code></pre>
<p><br/><br/></p>
<h2>工具类</h2>
<h3>签名工具类</h3>
<pre><code class="language-java">/**
* 生成签名信息
*
* @param appkey 产品私钥
* @param params 接口请求参数名和参数值,不包括sign参数名
* @return sign 签名摘要
*/
public static String genSignature(Map&lt;String, String&gt; params, String appkey) {
// 1. 参数名按照ASCII码表升序排序
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
// 2. 按照排序拼接参数名与参数值
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append(params.get(key));
}
// 3. 将appkey拼接到最后
sb.append(appkey);
System.out.println(&quot;原数据: &quot; + sb);
byte[] md = new byte[32];
// 4. SM3签名
byte[] msg1 = sb.toString().getBytes(StandardCharsets.UTF_8);
SM3Digest sm3 = new SM3Digest();
sm3.update(msg1, 0, msg1.length);
sm3.doFinal(md, 0);
String sign = new String(Hex.encode(md));
return sign;
}</code></pre>
<h3>HTTP工具类</h3>
<pre><code class="language-java"> /**
* @param url :请求接口地址
* @param params :参数
* @return jsonObject 请求结果
*/
public static JSONObject postRequest(String url, Map&lt;String, String&gt; params) {
try {
FormBody.Builder builder = new FormBody.Builder();
for (Map.Entry&lt;String, String&gt; m : params.entrySet()) {
builder.add(m.getKey(), m.getValue());
}
RequestBody body = builder.build();
Request request = new Request.Builder().post(body).url(url).build();
Response response = OkHttpUtil.getInstance().newCall(request).execute();
if (response.isSuccessful()) {
String content = response.body().string();
if (StringUtils.isNotBlank(content)) {
JSONObject jsonObject = JSONObject.parseObject(content);
return jsonObject;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}</code></pre>
<h3>密钥格式转换</h3>
<pre><code class="language-java"> /**
* @param salt :密钥因子
* @return result 密钥
*/
public static String getSecretKey(String salt) throws NoSuchAlgorithmException {
String result = &quot;&quot;;
MessageDigest md = MessageDigest.getInstance(&quot;MD5&quot;);
md.update(salt.getBytes());
byte[] byteResult = md.digest();
int i;
StringBuffer stringBuffer = new StringBuffer(&quot;&quot;);
for (int offset = 0; offset &lt; byteResult.length; offset++) {
i = byteResult[offset];
if (i &lt; 0) {
i += 256;
}
if (i &lt; 16) {
stringBuffer.append(&quot;0&quot;);
}
stringBuffer.append(Integer.toHexString(i));
}
result = stringBuffer.toString().substring(8, 24);
return result;
}</code></pre>
<p><br/><br/></p>
<h2>接口响应参数</h2>
<p>所有接口响应值采用 JSON 格式,如无特殊说明,每次请求的返回值中,都包含下面字段:</p>
<table>
<thead>
<tr>
<th style="text-align: left;">字段名</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">参数描述</th>
<th style="text-align: left;">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">code</td>
<td style="text-align: left;">int</td>
<td style="text-align: left;">响应代码</td>
<td style="text-align: left;">0表示成功,其他代码都为失败,详情参考附录。</td>
</tr>
<tr>
<td style="text-align: left;">msg</td>
<td style="text-align: left;">String</td>
<td style="text-align: left;">响应描述</td>
<td style="text-align: left;">响应代码描述</td>
</tr>
<tr>
<td style="text-align: left;">data</td>
<td style="text-align: left;">Object</td>
<td style="text-align: left;">数据内容</td>
<td style="text-align: left;">数据内容 </td>
</tr>
</tbody>
</table>
<h3>响应码</h3>
<p>响应码(code)是密认服务 API 调用的结果。当返回码不为 0 时,表示请求未正常执行,返回码描述 (msg) 对该结果进行了细化补充,用户可根据返回码判断 API 的执行情况。
所有接口调用返回值均包含 code 和 msg 字段,code 为返回码值,msg 为返回码描述信息,返回码表如下:</p>
<table>
<thead>
<tr>
<th style="text-align: left;">序号</th>
<th style="text-align: left;">参数</th>
<th style="text-align: left;">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">1</td>
<td style="text-align: left;">0</td>
<td style="text-align: left;">调用成功</td>
</tr>
<tr>
<td style="text-align: left;">2</td>
<td style="text-align: left;">1</td>
<td style="text-align: left;">错误描述参考 msg</td>
</tr>
<tr>
<td style="text-align: left;">3</td>
<td style="text-align: left;">1001</td>
<td style="text-align: left;">参数不能为空</td>
</tr>
<tr>
<td style="text-align: left;">4</td>
<td style="text-align: left;">1002</td>
<td style="text-align: left;">时间戳过期</td>
</tr>
<tr>
<td style="text-align: left;">5</td>
<td style="text-align: left;">1003</td>
<td style="text-align: left;">验签失败</td>
</tr>
<tr>
<td style="text-align: left;">6</td>
<td style="text-align: left;">1004</td>
<td style="text-align: left;">应用不存在</td>
</tr>
<tr>
<td style="text-align: left;">7</td>
<td style="text-align: left;">1005</td>
<td style="text-align: left;">应用已停用</td>
</tr>
<tr>
<td style="text-align: left;">8</td>
<td style="text-align: left;">1006</td>
<td style="text-align: left;">商户信息不存在</td>
</tr>
<tr>
<td style="text-align: left;">9</td>
<td style="text-align: left;">1007</td>
<td style="text-align: left;">重复请求</td>
</tr>
</tbody>
</table>