Merge branch 'cc_20250808_fixsign' into 'master'

兼容老的验签

See merge request hangzhou/java/custom_zxjp!146
This commit is contained in:
苏竹红
2025-08-11 01:43:42 +00:00
3 changed files with 90 additions and 23 deletions

View File

@@ -44,6 +44,41 @@ public class OpenSignatureUtil {
sb.append(key).append("=").append(JSONObject.toJSONString( value)).append("&");
});
// 3.2 添加固定参数(不参与排序)
sb.append("appkey=").append(appKey)
.append("&timestamp=").append(timestamp);
log.info("待签名字符串:{}", sb);
// 4. 生成签名
return hmacSha256(sb.toString(), appSecret);
}
public static String generateOldSign(Map<String, String> params, String appSecret) {
// 1. 分离固定参数和业务参数
String appKey = params.get("appKey");
String timestamp = params.get("timestamp");
// 2. 创建不包含固定参数的临时Map用于排序
Map<String, String> sortedParams = new TreeMap<>(
params.entrySet().stream()
.filter(e -> !"appKey".equals(e.getKey()))
.filter(e -> !"timestamp".equals(e.getKey()))
.filter(e -> !"sign".equals(e.getKey()))
.filter(e -> e.getValue() != null && !e.getValue().isEmpty())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
))
);
// 3. 构建参数字符串:业务参数(排序后) + 固定参数
StringBuilder sb = new StringBuilder();
// 3.1 添加排序后的业务参数
sortedParams.forEach((key, value) -> {
sb.append(key).append("=").append(value).append("&");
});
// 3.2 添加固定参数(不参与排序)
sb.append("appkey=").append(appKey)
.append("&timestamp=").append(timestamp);

View File

@@ -381,6 +381,8 @@ public class SignFranchiseServiceImpl implements SignFranchiseService, AuditResu
requestMap.put("shopId", String.valueOf(shopInfoDO.getId()));
commonService.sendMessage(new ArrayList<>(auditFranchiseFeeUsers), MessageEnum.MESSAGE_20, requestMap);
} else if (Constants.ONE_INTEGER.equals(request.getAuditResult())) {
log.info("合同审核,装修属性:{},加盟模式:{}",ShopDecorationAttributesEnum.getDescByCode(shopInfoDO.getShopDecorationAttributes()),
JoinModeEnum.getByCode(shopInfoDO.getJoinMode()));
if (shopInfoDO.getShopDecorationAttributes().equals(ShopDecorationAttributesEnum.OLD_NEW_OPEN.getCode())) {
//老店新开时装修与开业直接完成
shopStageInfoDAO.batchUpdateByShopIdsAndSubStageStatus(Arrays.asList(shopId), Arrays.asList(
@@ -388,7 +390,7 @@ public class SignFranchiseServiceImpl implements SignFranchiseService, AuditResu
));
}else{
//,加盟公司自有店->加盟公司建店 不推送数据 再crm中完成
if ( !shopInfoDO.getJoinMode().equals(JoinModeEnum.FRANCHISE_COMPANIES.getCode())){
if ( !shopInfoDO.getJoinMode().equals(JoinModeEnum.OWN_STORE.getCode())){
hqtAPIService.pushHqtBuild(getHqtBuildRequest(request.getShopId()));
}
shopStageInfoDAO.updateShopStageInfo(shopId, ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_861);

View File

@@ -1,4 +1,5 @@
package com.cool.store.config;
import com.alibaba.fastjson.JSON;
import com.cool.store.constants.CommonConstants;
import com.cool.store.enums.ErrorCodeEnum;
@@ -7,9 +8,11 @@ import com.cool.store.response.ResponseResult;
import com.cool.store.utils.OpenSignatureUtil;
import com.cool.store.utils.StringUtil;
import com.cool.store.utils.UUIDUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
@@ -21,9 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -42,7 +43,11 @@ public class OpenApiValidateFilter implements Filter {
private String coolAppKey;
@Value("${cool.api.secret}")
private String coolAppSecret;
// 接口映射 除了红圈通系统,云流水,新管家等使用旧的验签模式
private static final List<String> oldUrlMapping = new ArrayList<>(Arrays.asList(
"/zxjp/open/v1/statusRefresh","/zxjp/open/v1/changePaymentStatus",
"/zxjp/open/v1/getYlsToken", "/zxjp/open/v1/getStoreList",
"/zxjp/open/v1/changeReceiptStatus", "/zxjp/open/v1/getStoreUser"));
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@@ -58,7 +63,7 @@ public class OpenApiValidateFilter implements Filter {
}
MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
//statusRefresh 放开不需要验签
if(uri.startsWith("/zxjp/open/v1/")||uri.startsWith("/zxjp/open/v1/getStoreUser")){
if (uri.startsWith("/zxjp/open/v1/statusRefresh") || uri.startsWith("/zxjp/open/v1/getStoreUser")) {
filterChain.doFilter(servletRequest, response);
return;
}
@@ -67,15 +72,15 @@ public class OpenApiValidateFilter implements Filter {
try {
String timestampStr = request.getHeader("timestamp");
if (timestampStr == null) {
log.info("timestampStr is null {}","缺少timestamp参数");
log.info("timestampStr is null {}", "缺少timestamp参数");
res.setStatus(HttpStatus.OK.value());
res.setCharacterEncoding("UTF-8");
res.getWriter().write(JSON.toJSONString(
ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL,"缺少timestamp参数")));
ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL, "缺少timestamp参数")));
return;
}
long timestamp = Long.parseLong(timestampStr)/1000;
long currentTime = System.currentTimeMillis()/1000;
long timestamp = Long.parseLong(timestampStr) / 1000;
long currentTime = System.currentTimeMillis() / 1000;
long timeDiff = Math.abs(currentTime - timestamp);
try {
if (timeDiff > 1600) {
@@ -120,25 +125,20 @@ public class OpenApiValidateFilter implements Filter {
}
String jsonBody = requestBody.toString();
String serverSign;
if (oldUrlMapping.contains(uri)) {
serverSign = getOldSign(jsonBody, appKey, timestampStr);
} else {
serverSign = getNewSign(jsonBody, appKey, timestampStr);
}
// 2. 使用 Jackson 解析 JSON 并转为 TreeMap自动按键排序
ObjectMapper objectMapper = new ObjectMapper();
SortedMap<String, Object> params = objectMapper.readValue(
jsonBody,
new TypeReference<TreeMap<String, Object>>() {}
);
params.put("appKey",appKey);
params.put("timestamp", timestampStr);
String serverSign = OpenSignatureUtil.generateSign(params, coolAppSecret);
log.info("{}",serverSign);
log.info("serverSign{}", serverSign);
if (!serverSign.equalsIgnoreCase(clientSign)) {
res.setStatus(HttpStatus.OK.value());
res.setCharacterEncoding("UTF-8");
res.getWriter().write(JSON.toJSONString(
ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL,"签名校验失败")));
ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL, "签名校验失败")));
return;
}
filterChain.doFilter(request, response);
@@ -147,6 +147,36 @@ public class OpenApiValidateFilter implements Filter {
}
}
private @NotNull String getNewSign(String jsonBody, String appKey, String timestampStr) throws JsonProcessingException {
// 2. 使用 Jackson 解析 JSON 并转为 TreeMap自动按键排序
ObjectMapper objectMapper = new ObjectMapper();
SortedMap<String, Object> params = objectMapper.readValue(
jsonBody,
new TypeReference<TreeMap<String, Object>>() {
}
);
params.put("appKey", appKey);
params.put("timestamp", timestampStr);
return OpenSignatureUtil.generateSign(params, coolAppSecret);
}
private @NotNull String getOldSign(String jsonBody, String appKey, String timestampStr) throws JsonProcessingException {
// 2. 使用 Jackson 解析 JSON 并转为 TreeMap自动按键排序
ObjectMapper objectMapper = new ObjectMapper();
SortedMap<String, String> params = objectMapper.readValue(
jsonBody,
new TypeReference<TreeMap<String, String>>() {
}
);
params.put("appKey", appKey);
params.put("timestamp", timestampStr);
return OpenSignatureUtil.generateOldSign(params, coolAppSecret);
}
@Override
public void destroy() {
}