数商API技术文档

数商API技术文档


接口签名

<h2>1.RSA签名</h2> <h3>签名步骤:</h3> <ol> <li>参数通过ASCII码排序后使用RSA加密</li> <li>签名规则:SHA256WithRSA</li> </ol> <h5>在线RSA公钥私钥生成: <a href="https://www.btool.cn/rsa-key-pair-generator">https://www.btool.cn/rsa-key-pair-generator</a></h5> <p>Bits:2048</p> <h3>Demo:</h3> <h5>请求方式:POST</h5> <h5><strong>请求参数:</strong></h5> <pre><code>{&amp;quot;mobile&amp;quot;:&amp;quot;135****9272&amp;quot;,&amp;quot;platform&amp;quot;:&amp;quot;zwlm&amp;quot;,&amp;quot;source&amp;quot;:&amp;quot;ZST&amp;quot;,&amp;quot;app_id&amp;quot;:1,&amp;quot;ts&amp;quot;:1740385419}</code></pre> <h5>对关联数组按照键名进行升序排序</h5> <pre><code>app_id=1&amp;amp;mobile=135****9272&amp;amp;platform=zwlm&amp;amp;source=ZST&amp;amp;ts=1740385419</code></pre> <h5>排序后签名:</h5> <pre><code>DWPOEBBTHUr4z0zIu1SOtsw\/QC8HdObDRoBu5wshqwJjGhC5eAE6R2xtBcEQzP+aXlgD7fyQvX5K\/pTLI7MNVl4hFlzJBAJ3JkFhA9mlyOzAbtvoocXAw9nHKERPxnypFPDWghFHQDpKyM29ktMyGlG6XR8+nj4+fScvQHBnZM987iXu3c6xNT027meJMEXBkazxPwa664V5ylebgsvoWdl8sDx8WfVH8PiYLHEjWKGf9aKMp6Csuq5cnSNx\/CB1PDVmcyG9Xh5o1Aym8Zg23FXLLojIRKiRsTTuIE9IsRQDIMcQdbngFGg6bJ26jamedBnCRutbOQnIoRECGvS3Eg==</code></pre> <h5>PHP签名:</h5> <pre><code>/** * 获取签名 * @param $param * @param $privateKey * @return string */ private function getSignature($param,$privateKey) { if (isset($param[&amp;#039;sign&amp;#039;])) unset($param[&amp;#039;sign&amp;#039;]); ksort($param); $str = &amp;#039;&amp;#039;; foreach ($param as $k=&amp;gt;$item) { if (empty($item)) continue; if (!empty($str)) { $str .= &amp;#039;&amp;amp;&amp;#039;.$k.&amp;#039;=&amp;#039;.$item; } else { $str .= $k.&amp;#039;=&amp;#039;.$item; } } $str = trim($str, &amp;quot;&amp;amp;&amp;quot;); return self::getSHA256SignWithRSA($str, $privateKey); } /** * @Notes:生成 sha256WithRSA 签名 * 提示:SPKI(subject public key identifier,主题公钥标识符) * @param null $signContent 待签名内容 * @param string $privateKey 私钥数据(如果为单行,内容需要去掉RSA的标识符) * @return string 签名串 * @DateTime: 2024-04-29 */ public static function getSHA256SignWithRSA($signContent = null, string $privateKey = &amp;#039;&amp;#039;): string { //判断私钥是否可用 $key = openssl_pkey_get_private($privateKey); //开始加密 openssl_sign($signContent, $signature, $key, OPENSSL_ALGO_SHA256); //进行 base64编码 加密后内容 $encryptedStr = base64_encode($signature); return $encryptedStr; } /** * 签名校验 * @param $param * @param array $header * @param bool $date * @return false|int */ public static function checkSignature($param,$publicKey, array $header = [], bool $date = false) { if (!is_array($param) || empty($param[&amp;#039;sign&amp;#039;])) { return false; } if (empty($publicKey)) { return false; } $sign = $param[&amp;#039;sign&amp;#039;]; unset($param[&amp;#039;sign&amp;#039;], $param[&amp;#039;debug&amp;#039;]); ksort($param); $str = &amp;#039;&amp;#039;; foreach ($param as $k=&amp;gt;$item) { if (!empty($str)) { $str .= &amp;#039;&amp;amp;&amp;#039;.$k.&amp;#039;=&amp;#039;.$item; } else { $str .= $k.&amp;#039;=&amp;#039;.$item; } } //$str = http_build_query($param); $str = trim($str, &amp;quot;&amp;amp;&amp;quot;); if (!empty($param) &amp;amp;&amp;amp; $date) { $str .= date(&amp;#039;Y-m-d&amp;#039;); } //URL 中空格使用加号,使用 %2B 替换加号 $sign = str_replace([&amp;quot; &amp;quot;], &amp;quot;+&amp;quot;, $sign); $sign = str_replace([&amp;quot;\r&amp;quot;, &amp;quot;\n&amp;quot;, &amp;quot; &amp;quot;], &amp;quot;&amp;quot;, $sign); $ok = self::verifySha256SignWithRSA($str, $sign, $publicKey, false); return $ok; } /** * @Notes:验证 sha256WithRSA 签名 * @param null $signContent 待签名内容 * @param string $signatureStr 签名串 * @param string $public_key 公钥数据(如果为单行,内容需要去掉RSA的标识符) * @return int 1:签名成功,-1:签名失败 * @DateTime: 2024-04-29 */ public static function verifySha256SignWithRSA($signContent = null, string $signatureStr = &amp;#039;&amp;#039;, string $public_key = &amp;#039;&amp;#039;): int { //判断私钥是否可用 $key = openssl_get_publickey($public_key); return openssl_verify($signContent, base64_decode($signatureStr), $key, OPENSSL_ALGO_SHA256); }</code></pre> <h5>JAVA签名:</h5> <pre><code>import com.alibaba.fastjson2.JSONObject; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.jupiter.api.Test; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Iterator; import java.util.TreeMap; @Slf4j public class SignTest3 { @SneakyThrows @Test public void TestDemo() { Security.addProvider(new BouncyCastleProvider()); TreeMap&amp;lt;String, Object&amp;gt; map = new TreeMap&amp;lt;&amp;gt;(); map.put(&amp;quot;name1&amp;quot;, &amp;quot;asdfhgbcad&amp;quot;); map.put(&amp;quot;name2&amp;quot;, &amp;quot;哈哈哈&amp;quot;); map.put(&amp;quot;amount&amp;quot;, &amp;quot;123.12&amp;quot;); map.put(&amp;quot;timestamp&amp;quot;,&amp;quot;2021-05-07 16:00:12&amp;quot;); map.put(&amp;quot;randomStr&amp;quot;,&amp;quot;17150686881260658010&amp;quot;); System.out.print(&amp;quot;参数:&amp;quot;); System.out.println(new JSONObject(){{putAll(map);}}); map.put(&amp;quot;sign&amp;quot;, sign(map)); JSONObject json = new JSONObject() {{putAll(map);}}; boolean xx = checkSign(map); System.out.print(&amp;quot;验签:&amp;quot;); System.out.println(xx); } public static boolean checkSign(final TreeMap&amp;lt;String, Object&amp;gt; map) { map.remove(&amp;quot;key&amp;quot;); String stringSignTemp = createSignA(map); System.out.println(&amp;quot;排序:&amp;quot;+stringSignTemp); System.out.println(); return doCheck(stringSignTemp, String.valueOf(map.get(&amp;quot;sign&amp;quot;)),PUBLIC_KEY); } public static String sign(final TreeMap&amp;lt;String, Object&amp;gt; map) { map.remove(&amp;quot;key&amp;quot;); String stringSignTemp = createSignA(map); log.debug(&amp;quot;stringSignTemp:{}&amp;quot;, stringSignTemp); return signstr(stringSignTemp,PRIVATE_KEY); } public static String createSignA(JSONObject json) { TreeMap&amp;lt;String, Object&amp;gt; sortMap=new TreeMap&amp;lt;&amp;gt;(); sortMap.putAll(json); return createSignA(sortMap); } public static String createSignA(TreeMap&amp;lt;String, Object&amp;gt; sortMap) { StringBuilder sb = new StringBuilder(); if (sortMap != null &amp;amp;&amp;amp; !sortMap.isEmpty()) { Iterator var2 = sortMap.keySet().iterator(); while(var2.hasNext()) { String key = (String)var2.next(); if (StringUtils.isNotBlank(String.valueOf(sortMap.get(key))) &amp;amp;&amp;amp; !&amp;quot;sign&amp;quot;.equals(key)) { sb.append(key); sb.append(&amp;quot;=&amp;quot;); sb.append(sortMap.get(key)); sb.append(&amp;quot;&amp;amp;&amp;quot;); } } return sb.substring(0, sb.length() - 1); } else { return &amp;quot;&amp;quot;; } } public static String signstr(String signContent, String privateKey) { String signstr = null; try { signstr = encryptBASE64(sign(signContent, privateKey)); return signstr; } catch (Exception var4) { log.info(&amp;quot;RSASignature 签名加密异常&amp;quot;); throw new RuntimeException(var4); } } public static String encryptBASE64(byte[] key) throws Exception { String base64encodedString = Base64.getEncoder().encodeToString(key); return base64encodedString.replace(&amp;quot;\t&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\n&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\r&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\t&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\n&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\r&amp;quot;, &amp;quot;&amp;quot;); } public static byte[] sign(String content, String privateKey) { try { privateKey = privateKey.replace(&amp;quot;-----BEGIN RSA PRIVATE KEY-----\n&amp;quot;, &amp;quot;&amp;quot;); privateKey = privateKey.replace(&amp;quot;\n-----END RSA PRIVATE KEY-----&amp;quot;, &amp;quot;&amp;quot;); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decryptBASE64(privateKey)); KeyFactory keyf = KeyFactory.getInstance(&amp;quot;RSA&amp;quot;); PrivateKey priKey = keyf.generatePrivate(priPKCS8); Signature signature = Signature.getInstance(SIGN_ALGORITHMS); signature.initSign(priKey); signature.update(content.getBytes(&amp;quot;UTF-8&amp;quot;)); byte[] signed = signature.sign(); return signed; } catch (Exception var7) { var7.printStackTrace(); return null; } } public static boolean doCheck(String content, String sign, String publicKey) { try { publicKey = publicKey.replace(&amp;quot;-----BEGIN PUBLIC KEY-----\n&amp;quot;, &amp;quot;&amp;quot;); publicKey = publicKey.replace(&amp;quot;\n-----END PUBLIC KEY-----&amp;quot;, &amp;quot;&amp;quot;); KeyFactory keyFactory = KeyFactory.getInstance(&amp;quot;RSA&amp;quot;); byte[] encodedKey = decryptBASE64(publicKey); PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); Signature signature = signature=Signature.getInstance(SIGN_ALGORITHMS);; signature.initVerify(pubKey); signature.update(content.getBytes(&amp;quot;UTF-8&amp;quot;)); boolean bverify = signature.verify(decryptBASE64(sign)); return bverify; } catch (Exception var8) { var8.printStackTrace(); return false; } } public static byte[] decryptBASE64(String key) throws Exception { byte[] base64decodedBytes = Base64.getDecoder().decode(key.replace(&amp;quot;\t&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\n&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\r&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\t&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\n&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;\\r&amp;quot;, &amp;quot;&amp;quot;)); return base64decodedBytes; } static String SIGN_ALGORITHMS=&amp;quot;SHA256WITHRSA&amp;quot;; /*demo测试key 应用其他场景需自行生成配置*/ static String PRIVATE_KEY= &amp;quot;-----BEGIN RSA PRIVATE KEY-----\n&amp;quot; + &amp;quot;MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDgOeVX4u5mDXcZ\n&amp;quot; + &amp;quot;mcGwfUcH0IRbJRaO3PKEA6TDHoDQY9uil+S3qv3zdKbKW6Xyq0a8kaIdAZLipCsU\n&amp;quot; + &amp;quot;HzcNYsZP+rVATItt17VoN98XdgYhFfCPS0wyIu+GGKZxRatXFtn9yTf85kIs1El9\n&amp;quot; + &amp;quot;PKZ9vW44cjJo+htL49zvD3vG\n&amp;quot; + &amp;quot;-----END RSA PRIVATE KEY-----&amp;quot;; static String PUBLIC_KEY=&amp;quot;-----BEGIN PUBLIC KEY-----\n&amp;quot; + &amp;quot;MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4DnlV+LuZg13GZnBsH1H\n&amp;quot; + &amp;quot;B9CEWyUWjtzyhAOkwx6A0GPbopfkt6r983Smylul8qtGvJGiHQGS4qQrFB83DWLG\n&amp;quot; + &amp;quot;jQIDAQAB\n&amp;quot; + &amp;quot;-----END PUBLIC KEY-----&amp;quot;; } </code></pre>

页面列表

ITEM_HTML