|
|
@@ -40,17 +40,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
-import java.security.InvalidKeyException;
|
|
|
-import java.security.NoSuchAlgorithmException;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
-import javax.crypto.Mac;
|
|
|
-import javax.crypto.spec.SecretKeySpec;
|
|
|
-
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
@@ -561,18 +555,18 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- // 标准 HMAC-SHA256 签名验证算法:
|
|
|
+ // 哈哈平台签名验证算法:
|
|
|
// 1. 排除 sign、sign_type 等签名相关字段
|
|
|
// 2. 剩余参数按 key 字典序升序排列
|
|
|
// 3. 拼接为 key1=value1&key2=value2&...&keyN=valueN 格式
|
|
|
- // 4. 使用 appSecret 作为密钥计算 HMAC-SHA256
|
|
|
- // 5. 将结果转换为小写十六进制字符串,与 sign 参数比对
|
|
|
- //
|
|
|
- // 注意:如果哈哈平台的签名算法不同(如 MD5、拼接方式差异),
|
|
|
- // 请根据平台文档调整下面的实现。
|
|
|
+ // 4. 末尾拼接 &appsecret=<secret>
|
|
|
+ // 5. 对拼接后的字符串进行 MD5,得到签名值
|
|
|
+ // 参考: haha-sdk SignUtils.generateSign()
|
|
|
|
|
|
String signContent = buildSignContent(params);
|
|
|
- String computedSign = hmacSha256(signContent, appSecret);
|
|
|
+ // 哈哈平台签名规则: 在参数字符串末尾拼接 &appsecret=<secret>,然后 MD5
|
|
|
+ String signStr = signContent + "&appsecret=" + appSecret;
|
|
|
+ String computedSign = md5(signStr);
|
|
|
|
|
|
boolean isValid = computedSign.equalsIgnoreCase(receivedSign);
|
|
|
if (!isValid) {
|
|
|
@@ -583,12 +577,6 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
}
|
|
|
return isValid;
|
|
|
|
|
|
- } catch (NoSuchAlgorithmException e) {
|
|
|
- log.error("HMAC-SHA256 算法不可用", e);
|
|
|
- return false;
|
|
|
- } catch (InvalidKeyException e) {
|
|
|
- log.error("签名密钥无效", e);
|
|
|
- return false;
|
|
|
} catch (Exception e) {
|
|
|
log.error("签名验证异常", e);
|
|
|
return false;
|
|
|
@@ -610,27 +598,20 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * HMAC-SHA256 计算
|
|
|
+ * MD5 加密(32位小写十六进制)
|
|
|
*/
|
|
|
- private String hmacSha256(String data, String key)
|
|
|
- throws NoSuchAlgorithmException, InvalidKeyException {
|
|
|
- Mac mac = Mac.getInstance("HmacSHA256");
|
|
|
- SecretKeySpec secretKeySpec = new SecretKeySpec(
|
|
|
- key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
|
|
- mac.init(secretKeySpec);
|
|
|
- byte[] result = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
|
|
- return bytesToHex(result);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 字节数组转小写十六进制字符串
|
|
|
- */
|
|
|
- private String bytesToHex(byte[] bytes) {
|
|
|
- StringBuilder sb = new StringBuilder();
|
|
|
- for (byte b : bytes) {
|
|
|
- sb.append(String.format("%02x", b));
|
|
|
+ private String md5(String str) {
|
|
|
+ try {
|
|
|
+ java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
|
|
+ byte[] bytes = md.digest(str.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (byte b : bytes) {
|
|
|
+ sb.append(String.format("%02x", b));
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ } catch (java.security.NoSuchAlgorithmException e) {
|
|
|
+ throw new RuntimeException("MD5 算法不可用", e);
|
|
|
}
|
|
|
- return sb.toString();
|
|
|
}
|
|
|
|
|
|
private void saveDeviceStatusToRedis(String deviceId, String activityId, String doorStatus, String openType, String outUserId) {
|