聚合支付接口文档

聚合支付接口文档


【JAVA】签名DEMO

<h2>签名DEMO</h2> <h3>1. 签名规则</h3> <ol> <li>将 <strong>加密后</strong> 的请求参数按照 a-z 排序并用【&amp;】拼接,如【a=1&amp;b=2&amp;c=3】</li> <li>在参数拼接后,拼接 <strong>商户KEY</strong> ,得到【a=1&amp;b=2&amp;c=3&amp;key=&quot;keyStr&quot;】</li> <li>将拼接完成的字符串通过 <code>MD5</code> 加密,结果转为大写,得到【sign】值</li> <li>将【sign】和【timestamp】和【merchantNo】添加到请求的JSON数据里</li> <li>验签通过前面的签名方式,获取到【sign】再对比接口参数里的【sign】对比是否一致</li> </ol> <h3>签名工具类 DEMO</h3> <pre><code class="language-java"> import com.alibaba.fastjson2.JSONObject; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class SignUtils { //忽略 加密、签名 字段 public final static List&amp;lt;String&amp;gt; neglectParams = List.of(&amp;quot;sign&amp;quot;, &amp;quot;timestamp&amp;quot;, &amp;quot;merchantNo&amp;quot;); /** * 参数 验签、解密 * * @param param 解密前参数JSON * @param key 商户KEY */ public static void verifyParam(JSONObject param, String key) { String timestamp = param.getString(&amp;quot;timestamp&amp;quot;); //验签 boolean checkSign = SignUtils.verifySignature(param, key); if (!checkSign) { throw new RuntimeException(&amp;quot;验签失败!&amp;quot;); } //获取AES-key String AesKey = AESUtils.sha256(timestamp); //参数解密 AESUtils.decrypt(param, AesKey); } /** * 参数 加密、签名 * * @param param 加密前参数JSON * @param key 商户KEY */ public static void encryptAndSign(JSONObject param, String key) { //获取AesKey Long timestamp = System.currentTimeMillis(); String AesKey = AESUtils.sha256(String.valueOf(timestamp)); // 生成随机16位,密钥 //数据加密 AESUtils.encrypt(param, AesKey); //签名 String sign = SignUtils.generateSignature(param, key); param.put(&amp;quot;sign&amp;quot;, sign); param.put(&amp;quot;timestamp&amp;quot;, timestamp); } /** * 生成签名 * * @param params 请求参数,包含所有需要签名的字段 * @param secretKey 商户密钥 * @return 生成的签名 */ public static String generateSignature(JSONObject params, String secretKey) { // 步骤1:去除空值的参数,排序并拼接成字符串 String stringA = createQueryString(params); // 步骤2:拼接密钥 String stringSignTemp = stringA + &amp;quot;&amp;amp;key=&amp;quot; + secretKey; // 步骤3:MD5运算,结果转换为大写 return md5(stringSignTemp).toUpperCase(); } /** * 验证签名 * * @param params 请求参数,包含所有需要签名的字段 * @param secretKey 商户密钥 * @return 验签结果,true表示签名合法,false表示签名不合法 */ public static boolean verifySignature(JSONObject params, String secretKey) { String sign = params.getString(&amp;quot;sign&amp;quot;); // 重新生成签名,并与传入的sign进行对比 String generatedSign = generateSignature(params, secretKey); return generatedSign.equals(sign); } /** * 根据参数构建URL编码的查询字符串,按照字典序排序 * * @param params 请求参数 * @return 拼接后的查询字符串 */ private static String createQueryString(JSONObject params) { // 1. 排序,按字典序排列参数 List&amp;lt;String&amp;gt; keys = new ArrayList&amp;lt;&amp;gt;(params.keySet()); Collections.sort(keys); StringBuilder queryString = new StringBuilder(); // 2. 遍历所有参数,拼接 key=value for (String key : keys) { if (neglectParams.contains(key)) { continue; } String value = params.getString(key); if (value != null &amp;amp;&amp;amp; !value.trim().isEmpty()) { // 排除值为空的参数 if (!queryString.isEmpty()) { queryString.append(&amp;quot;&amp;amp;&amp;quot;); } queryString.append(key).append(&amp;quot;=&amp;quot;).append(value); } } return queryString.toString(); } /** * MD5加密 * * @param input 输入字符串 * @return MD5加密后的结果 */ private static String md5(String input) { try { MessageDigest md = MessageDigest.getInstance(&amp;quot;MD5&amp;quot;); byte[] hash = md.digest(input.getBytes()); StringBuilder hexString = new StringBuilder(); for (byte b : hash) { String hex = Integer.toHexString(0xFF &amp;amp; b); if (hex.length() == 1) { hexString.append(&amp;#039;0&amp;#039;); } hexString.append(hex); } return hexString.toString(); } catch (Exception e) { throw new RuntimeException(&amp;quot;MD5 encryption error&amp;quot;, e); } } public static void main(String[] args) { String str = &amp;quot;{\n&amp;quot; + &amp;quot; \&amp;quot;merchantNo\&amp;quot;: 17178557819911016395,\n&amp;quot; + &amp;quot; \&amp;quot;merchantOrderNo\&amp;quot;: \&amp;quot;NO1234567890\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;payChannelId\&amp;quot;: 2,\n&amp;quot; + &amp;quot; \&amp;quot;channelCode\&amp;quot;: \&amp;quot;LeShua\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;amount\&amp;quot;: 1,\n&amp;quot; + &amp;quot; \&amp;quot;goodsDetail\&amp;quot;: \&amp;quot;{\\\&amp;quot;costPrice\\\&amp;quot;:1,\\\&amp;quot;receiptId\\\&amp;quot;:\\\&amp;quot;NO123\\\&amp;quot;,\\\&amp;quot;details\\\&amp;quot;:[{\\\&amp;quot;goodsId\\\&amp;quot;:\\\&amp;quot;1\\\&amp;quot;,\\\&amp;quot;wxGoodsId\\\&amp;quot;:\\\&amp;quot;2\\\&amp;quot;,\\\&amp;quot;goodsName\\\&amp;quot;:\\\&amp;quot;测试商品\\\&amp;quot;,\\\&amp;quot;quantity\\\&amp;quot;:1,\\\&amp;quot;price\\\&amp;quot;:1}]}\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;wechatInfo\&amp;quot;: \&amp;quot;{\\\&amp;quot;openId\\\&amp;quot;:\\\&amp;quot;oxX4F7Intpo6xi9Zc64VXrKcJW34\\\&amp;quot;,\\\&amp;quot;appid\\\&amp;quot;:\\\&amp;quot;wx55df9726a583666a\\\&amp;quot;}\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;notifyUrl\&amp;quot;: \&amp;quot;https://abc/abc\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;clientIp\&amp;quot;: \&amp;quot;127.0.0.1\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;attach\&amp;quot;:\&amp;quot;附加信息\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;description\&amp;quot;:\&amp;quot;商品A\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;supportFapiao\&amp;quot;:\&amp;quot;false\&amp;quot;,\n&amp;quot; + &amp;quot; \&amp;quot;sceneInfo\&amp;quot;:\&amp;quot;{\\\&amp;quot;id\\\&amp;quot;:\\\&amp;quot;123\\\&amp;quot;,\\\&amp;quot;name\\\&amp;quot;:\\\&amp;quot;门店\\\&amp;quot;,\\\&amp;quot;areaCode\\\&amp;quot;:\\\&amp;quot;101010\\\&amp;quot;,\\\&amp;quot;address\\\&amp;quot;:\\\&amp;quot;详细地址\\\&amp;quot;}\&amp;quot;&amp;quot; + &amp;quot;}&amp;quot;; JSONObject param = JSONObject.parseObject(str); encryptAndSign(param, &amp;quot;6E198B98647DB12C5C0A1825E8638354&amp;quot;); System.out.println(param); } } </code></pre>

页面列表

ITEM_HTML