feat:签名
This commit is contained in:
@@ -5,9 +5,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -110,4 +111,86 @@ public class OpenSignatureUtil {
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造签名串
|
||||
* @param params 参数Map
|
||||
* @return 构造好的签名串
|
||||
*/
|
||||
public static String buildSignString(Map<String, String> params) {
|
||||
return params.entrySet().stream()
|
||||
// 过滤空值字段
|
||||
.filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty())
|
||||
// 按参数名 ASCII 码升序排序
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
// 格式化为 key=value,值进行URL编码
|
||||
.map(entry -> {
|
||||
try {
|
||||
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
|
||||
return entry.getKey() + "=" + encodedValue;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("URL编码失败", e);
|
||||
}
|
||||
})
|
||||
// 用 & 连接
|
||||
.collect(Collectors.joining("&"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用私钥对签名串进行 RSA-SHA256 签名
|
||||
* @param signString 待签名的字符串
|
||||
* @param privateKeyStr Base64编码的私钥
|
||||
* @return Base64编码的签名
|
||||
*/
|
||||
public static String signWithRsaSha256(String signString, String privateKeyStr) {
|
||||
try {
|
||||
// 1. 解码Base64私钥
|
||||
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
|
||||
|
||||
// 2. 创建PKCS8编码密钥规范
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
|
||||
|
||||
// 3. 获取RSA KeyFactory
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
|
||||
// 4. 生成私钥对象
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
|
||||
|
||||
// 5. 创建Signature实例,使用SHA256withRSA算法
|
||||
Signature signature = Signature.getInstance("SHA256withRSA");
|
||||
signature.initSign(privateKey);
|
||||
|
||||
// 6. 更新要签名的数据
|
||||
signature.update(signString.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 7. 执行签名
|
||||
byte[] digitalSignature = signature.sign();
|
||||
|
||||
// 8. 对签名结果进行Base64编码
|
||||
return Base64.getEncoder().encodeToString(digitalSignature);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("RSA-SHA256签名失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的签名生成方法
|
||||
* @param params 参数Map
|
||||
* @param privateKeyStr 私钥字符串
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static String generateSignature(Map<String, String> params, String privateKeyStr) {
|
||||
// 1. 构造签名串
|
||||
String signString = buildSignString(params);
|
||||
log.info("待签名串: {}", signString);
|
||||
|
||||
// 2. 使用私钥进行RSA-SHA256签名
|
||||
String signature = signWithRsaSha256(signString, privateKeyStr);
|
||||
log.info("生成签名: {}", signature);
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.cool.store.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
*RSA-SHA256 验签工具类
|
||||
* @Author suzhuhong
|
||||
* @Date 2025/11/12 15:15
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class VerifySignatureUtils {
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
* @param params 参数Map(包含sign字段)
|
||||
* @param publicKeyStr Base64编码的公钥
|
||||
* @return 验签结果
|
||||
*/
|
||||
public static boolean verifySignature(Map<String, String> params, String publicKeyStr) {
|
||||
try {
|
||||
// 1. 从参数中提取签名(并移除,不参与签名串构造)
|
||||
String receivedSignature = params.get("sign");
|
||||
if (receivedSignature == null || receivedSignature.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("签名参数sign不能为空");
|
||||
}
|
||||
|
||||
// 2. 创建参数的副本,移除sign字段
|
||||
Map<String, String> paramsForSign = new HashMap<>(params);
|
||||
paramsForSign.remove("sign");
|
||||
|
||||
// 3. 构造签名串(与签名方相同的规则)
|
||||
String signString = buildSignString(paramsForSign);
|
||||
log.info("验签待签名串: {}", signString);
|
||||
|
||||
// 4. 验证签名
|
||||
return verifyRsaSha256(signString, receivedSignature, publicKeyStr);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("验签过程异常: ", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造签名串(与签名方相同的逻辑)
|
||||
*/
|
||||
private static String buildSignString(Map<String, String> params) {
|
||||
return params.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty())
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> {
|
||||
try {
|
||||
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
|
||||
return entry.getKey() + "=" + encodedValue;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("URL编码失败", e);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.joining("&"));
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA-SHA256 验签
|
||||
*/
|
||||
private static boolean verifyRsaSha256(String data, String signature, String publicKeyStr) {
|
||||
try {
|
||||
// 1. 解码Base64公钥
|
||||
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
|
||||
|
||||
// 2. 创建X509编码密钥规范
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
|
||||
|
||||
// 3. 获取RSA KeyFactory
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
|
||||
// 4. 生成公钥对象
|
||||
PublicKey publicKey = keyFactory.generatePublic(keySpec);
|
||||
|
||||
// 5. 创建Signature实例
|
||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
||||
sig.initVerify(publicKey);
|
||||
|
||||
// 6. 更新要验证的数据
|
||||
sig.update(data.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 7. 解码收到的签名
|
||||
byte[] signatureBytes = Base64.getDecoder().decode(signature);
|
||||
|
||||
// 8. 执行验证
|
||||
return sig.verify(signatureBytes);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("RSA-SHA256验签失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user