1.签名生成
<h1>1、签名sign生成约定</h1>
<p>算法规则
融赋通平台当前支持两种通信报文的安全签名方式:
第1种:通过与商户约定对应秘钥串对指定数据进行签名
第2种:通过商户私钥对指定数据进行签名
两种方式,需要作为指定数据的字符串生成规则均相同。
分三步完成:
第一步,设所有发送或者接收到的json数据域为集合M(不包括sign),将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…),(注:对循环数组子域需转换成key[index].subkey=subvalue形式,其中key为body下第一级数据标签,index为数组元素从0开始序号,subkey为数组元素名称,subvalue为数组元素subkey对应的值)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写
第二步,对于采取对称秘钥签名的商户,直接在该字符串后追加其商户对应的秘钥串键值对(&key=${secretKey}),生成待签名字符串,然后通过SHA256生成摘要字节数组,并进行BASE64编码,作为sign的值。
对于采取非对称签名的商户,使用商户私钥对该指定数据生成签名字节数组,并进行BASE64编码,作为sign的值。
第三步,将sign值追加到json上送对象中</p>
<h1>2、签名生成过程</h1>
<h2>1)、上送报文,加签前(举例)</h2>
<pre><code>{
&quot;merchant_id&quot;: &quot;testMerchant001&quot;,
&quot;partner_id&quot;: &quot;RFT&quot;,
&quot;timestamp&quot;: &quot;20180924235824387&quot;,
&quot;sign_type&quot;: &quot;SHA256&quot;
}</code></pre>
<h2>2)、把所有参数根据参数名k排序(升序)并拼接</h2>
<pre><code>merchant_id=testMerchant001&amp;partner_id=RFT&amp;sign_type=SHA256&amp;timestamp=20180924235824387</code></pre>
<h2>3)、追加签名密钥signGenerationKey(从融赋通获取,如:key=282b00eb561b455caac86925c6xxxxxx)</h2>
<pre><code>merchant_id=testMerchant001&amp;partner_id=RFT&amp;sign_type=SHA256&amp;timestamp=20180924235824387&amp;key=282b00eb561b455caac86925c6xxxxxx</code></pre>
<h2>4)、生成签名并base64</h2>
<pre><code>0g02YUW2fRRrAaMlYrwUmVAS1rb6loTJQ+4ffFNB7DM=</code></pre>
<h2>5)、最终上送报文</h2>
<pre><code>{
&quot;merchant_id&quot;: &quot;testMerchant001&quot;,
&quot;partner_id&quot;: &quot;RFT&quot;,
&quot;timestamp&quot;: &quot;20180924235824387&quot;,
&quot;sign_type&quot;: &quot;SHA256&quot;,
&quot;sign&quot;: &quot;0g02YUW2fRRrAaMlYrwUmVAS1rb6loTJQ+4ffFNB7DM=&quot;
}</code></pre>
<h1>3、生成签名代码参考</h1>
<pre><code> public static void main(String[] args) {
// 从融赋通获取
String signGenerationKey = &quot;282b00eb561b455caac86925c6xxxxxx&quot;;
// 举例输入参数
String param = &quot;{\n&quot; +
&quot; \&quot;ret_msg\&quot;: \&quot;操作完成\&quot;,\n&quot; +
&quot; \&quot;ret_code\&quot;: \&quot;0000\&quot;,\n&quot; +
&quot; \&quot;sign_type\&quot;: \&quot;SHA256\&quot;,\n&quot; +
&quot; \&quot;ret_data\&quot;: {\n&quot; +
&quot; \&quot;deal_no\&quot;: \&quot;20230613100225000493\&quot;,\n&quot; +
&quot; \&quot;signed_code\&quot;: \&quot;S\&quot;,\n&quot; +
&quot; \&quot;signed_msg\&quot;: \&quot;成功\&quot;,\n&quot; +
&quot; \&quot;serial_no\&quot;: \&quot;M201811082322120002\&quot;\n&quot; +
&quot; },\n&quot; +
&quot; \&quot;timestamp\&quot;: \&quot;20230613112733080\&quot;\n&quot; +
&quot;}&quot;;
JSONObject jsonObject = JSON.parseObject(param);
// 参数排序
String paramSort = getSortKVStr(jsonObject);
System.out.println(paramSort);
// 追加签名密钥signGenerationKey
String paramSortAppendkey = paramSort + &quot;&amp;key=&quot; + signGenerationKey;
System.out.println(paramSortAppendkey);
try {
MessageDigest digest = MessageDigest.getInstance(&quot;SHA-256&quot;);
// 执行加签转base64
byte[] paramHash = digest.digest(paramSortAppendkey.getBytes(StandardCharsets.UTF_8));
String base64Sign = Base64.getEncoder().encodeToString(paramHash);
System.out.println(&quot;Base64 encoded SHA256 hash: &quot; + base64Sign);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 参数排序
* @param values
* @return 排序后输出String
*/
private static String getSortKVStr(Map&lt;String, Object&gt; values) {
List&lt;String&gt; keys = new ArrayList&lt;&gt;(values.keySet());
Collections.sort(keys);
StringBuilder sb = new StringBuilder();
for (String key : keys) {
//附件不参与签名验签
if (&quot;file&quot;.equals(key)) {
continue;
}
Object value = values.get(key);
if (value == null || &quot;&quot;.equals(value)) {
continue;
}
if (sb.length() &gt; 0)
sb.append('&amp;');
sb.append(key).append(&quot;=&quot;).append(value);
}
String sortKVStr = sb.toString();
System.out.println(&quot;sort kv string for sign:&quot; + sortKVStr);
return sortKVStr;
}</code></pre>