接口签名
<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>{&quot;mobile&quot;:&quot;135****9272&quot;,&quot;platform&quot;:&quot;zwlm&quot;,&quot;source&quot;:&quot;ZST&quot;,&quot;app_id&quot;:1,&quot;ts&quot;:1740385419}</code></pre>
<h5>对关联数组按照键名进行升序排序</h5>
<pre><code>app_id=1&amp;mobile=135****9272&amp;platform=zwlm&amp;source=ZST&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[&#039;sign&#039;])) unset($param[&#039;sign&#039;]);
ksort($param);
$str = &#039;&#039;;
foreach ($param as $k=&gt;$item) {
if (empty($item)) continue;
if (!empty($str)) {
$str .= &#039;&amp;&#039;.$k.&#039;=&#039;.$item;
} else {
$str .= $k.&#039;=&#039;.$item;
}
}
$str = trim($str, &quot;&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 = &#039;&#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[&#039;sign&#039;])) {
return false;
}
if (empty($publicKey)) {
return false;
}
$sign = $param[&#039;sign&#039;];
unset($param[&#039;sign&#039;], $param[&#039;debug&#039;]);
ksort($param);
$str = &#039;&#039;;
foreach ($param as $k=&gt;$item) {
if (!empty($str)) {
$str .= &#039;&amp;&#039;.$k.&#039;=&#039;.$item;
} else {
$str .= $k.&#039;=&#039;.$item;
}
}
//$str = http_build_query($param);
$str = trim($str, &quot;&amp;&quot;);
if (!empty($param) &amp;&amp; $date) {
$str .= date(&#039;Y-m-d&#039;);
}
//URL 中空格使用加号,使用 %2B 替换加号
$sign = str_replace([&quot; &quot;], &quot;+&quot;, $sign);
$sign = str_replace([&quot;\r&quot;, &quot;\n&quot;, &quot; &quot;], &quot;&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 = &#039;&#039;, string $public_key = &#039;&#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&lt;String, Object&gt; map = new TreeMap&lt;&gt;();
map.put(&quot;name1&quot;, &quot;asdfhgbcad&quot;);
map.put(&quot;name2&quot;, &quot;哈哈哈&quot;);
map.put(&quot;amount&quot;, &quot;123.12&quot;);
map.put(&quot;timestamp&quot;,&quot;2021-05-07 16:00:12&quot;);
map.put(&quot;randomStr&quot;,&quot;17150686881260658010&quot;);
System.out.print(&quot;参数:&quot;);
System.out.println(new JSONObject(){{putAll(map);}});
map.put(&quot;sign&quot;, sign(map));
JSONObject json = new JSONObject() {{putAll(map);}};
boolean xx = checkSign(map);
System.out.print(&quot;验签:&quot;);
System.out.println(xx);
}
public static boolean checkSign(final TreeMap&lt;String, Object&gt; map) {
map.remove(&quot;key&quot;);
String stringSignTemp = createSignA(map);
System.out.println(&quot;排序:&quot;+stringSignTemp);
System.out.println();
return doCheck(stringSignTemp, String.valueOf(map.get(&quot;sign&quot;)),PUBLIC_KEY);
}
public static String sign(final TreeMap&lt;String, Object&gt; map) {
map.remove(&quot;key&quot;);
String stringSignTemp = createSignA(map);
log.debug(&quot;stringSignTemp:{}&quot;, stringSignTemp);
return signstr(stringSignTemp,PRIVATE_KEY);
}
public static String createSignA(JSONObject json) {
TreeMap&lt;String, Object&gt; sortMap=new TreeMap&lt;&gt;();
sortMap.putAll(json);
return createSignA(sortMap);
}
public static String createSignA(TreeMap&lt;String, Object&gt; sortMap) {
StringBuilder sb = new StringBuilder();
if (sortMap != null &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; !&quot;sign&quot;.equals(key)) {
sb.append(key);
sb.append(&quot;=&quot;);
sb.append(sortMap.get(key));
sb.append(&quot;&amp;&quot;);
}
}
return sb.substring(0, sb.length() - 1);
} else {
return &quot;&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(&quot;RSASignature 签名加密异常&quot;);
throw new RuntimeException(var4);
}
}
public static String encryptBASE64(byte[] key) throws Exception {
String base64encodedString = Base64.getEncoder().encodeToString(key);
return base64encodedString.replace(&quot;\t&quot;, &quot;&quot;).replace(&quot;\n&quot;, &quot;&quot;).replace(&quot;\r&quot;, &quot;&quot;).replace(&quot;\\t&quot;, &quot;&quot;).replace(&quot;\\n&quot;, &quot;&quot;).replace(&quot;\\r&quot;, &quot;&quot;);
}
public static byte[] sign(String content, String privateKey) {
try {
privateKey = privateKey.replace(&quot;-----BEGIN RSA PRIVATE KEY-----\n&quot;, &quot;&quot;);
privateKey = privateKey.replace(&quot;\n-----END RSA PRIVATE KEY-----&quot;, &quot;&quot;);
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decryptBASE64(privateKey));
KeyFactory keyf = KeyFactory.getInstance(&quot;RSA&quot;);
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update(content.getBytes(&quot;UTF-8&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(&quot;-----BEGIN PUBLIC KEY-----\n&quot;, &quot;&quot;);
publicKey = publicKey.replace(&quot;\n-----END PUBLIC KEY-----&quot;, &quot;&quot;);
KeyFactory keyFactory = KeyFactory.getInstance(&quot;RSA&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(&quot;UTF-8&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(&quot;\t&quot;, &quot;&quot;).replace(&quot;\n&quot;, &quot;&quot;).replace(&quot;\r&quot;, &quot;&quot;).replace(&quot;\\t&quot;, &quot;&quot;).replace(&quot;\\n&quot;, &quot;&quot;).replace(&quot;\\r&quot;, &quot;&quot;));
return base64decodedBytes;
}
static String SIGN_ALGORITHMS=&quot;SHA256WITHRSA&quot;;
/*demo测试key 应用其他场景需自行生成配置*/
static String PRIVATE_KEY= &quot;-----BEGIN RSA PRIVATE KEY-----\n&quot; +
&quot;MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDgOeVX4u5mDXcZ\n&quot; +
&quot;mcGwfUcH0IRbJRaO3PKEA6TDHoDQY9uil+S3qv3zdKbKW6Xyq0a8kaIdAZLipCsU\n&quot; +
&quot;HzcNYsZP+rVATItt17VoN98XdgYhFfCPS0wyIu+GGKZxRatXFtn9yTf85kIs1El9\n&quot; +
&quot;PKZ9vW44cjJo+htL49zvD3vG\n&quot; +
&quot;-----END RSA PRIVATE KEY-----&quot;;
static String PUBLIC_KEY=&quot;-----BEGIN PUBLIC KEY-----\n&quot; +
&quot;MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4DnlV+LuZg13GZnBsH1H\n&quot; +
&quot;B9CEWyUWjtzyhAOkwx6A0GPbopfkt6r983Smylul8qtGvJGiHQGS4qQrFB83DWLG\n&quot; +
&quot;jQIDAQAB\n&quot; +
&quot;-----END PUBLIC KEY-----&quot;;
}
</code></pre>