Skip to content

Commit befa9de

Browse files
committed
feat: 支持长参数签名生成并保持客户端兼容性
test: 更新测试客户端添加版本头信息
1 parent 38ac211 commit befa9de

2 files changed

Lines changed: 115 additions & 2 deletions

File tree

app/application/src/main/java/com/alipay/application/service/system/utils/DigestSignUtils.java

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ private boolean isValidTimestamp(String timeStamp) {
221221

222222
/**
223223
* Generate SHA-256 signature including request parameters
224+
* Modified to support long parameters and maintain compatibility with client-side signature generation
224225
*
225226
* @param request the HTTP servlet request
226227
* @param accessKey the access key
@@ -230,8 +231,8 @@ private boolean isValidTimestamp(String timeStamp) {
230231
*/
231232
private static String generateSignatureWithParams(HttpServletRequest request, String accessKey, String timeStamp, String secretKey) {
232233
try {
233-
// Get all request parameters and build sorted parameter string
234-
Map<String, String> allParams = getAllRequestParams(request);
234+
// Get all request parameters without length filtering to support long parameters
235+
Map<String, String> allParams = getAllRequestParamsWithoutLengthFilter(request);
235236
String sortedParamString = buildSortedParamString(allParams);
236237

237238
// Use secure string concatenation with delimiter: accessKey|timestamp|sortedParams|secretKey
@@ -287,6 +288,49 @@ private static Map<String, String> getAllRequestParams(HttpServletRequest reques
287288

288289
return params;
289290
}
291+
292+
/**
293+
* Get all request parameters from the HTTP request without length filtering
294+
* Supports both URL query parameters and JSON request body parameters
295+
* This method is used for signature generation to support long parameters
296+
*
297+
* @param request the HTTP servlet request
298+
* @return map of all request parameters without length restrictions
299+
*/
300+
private static Map<String, String> getAllRequestParamsWithoutLengthFilter(HttpServletRequest request) {
301+
LinkedHashMap<String, String> params = new LinkedHashMap<>();
302+
303+
// Get URL query parameters without length filtering
304+
Enumeration<String> paramNames = request.getParameterNames();
305+
while (paramNames.hasMoreElements()) {
306+
String paramName = paramNames.nextElement();
307+
String paramValue = request.getParameter(paramName);
308+
// Only exclude authentication-related parameters, no length validation
309+
if (paramValue != null && !ACCESS_KEY_NAME.equals(paramName)
310+
&& !TIMESTAMP.equals(paramName) && !SIGN.equals(paramName)) {
311+
params.put(paramName, paramValue);
312+
}
313+
}
314+
315+
// Extract parameters from JSON request body for POST requests without length filtering
316+
if ("POST".equalsIgnoreCase(request.getMethod())) {
317+
String contentType = request.getContentType();
318+
if (contentType != null && contentType.toLowerCase().contains("application/json")) {
319+
Map<String, String> jsonParams = extractJsonParamsWithoutLengthFilter(request);
320+
// Merge JSON parameters with query parameters, JSON params take precedence
321+
for (Map.Entry<String, String> entry : jsonParams.entrySet()) {
322+
String paramName = entry.getKey();
323+
String paramValue = entry.getValue();
324+
if (paramValue != null && !ACCESS_KEY_NAME.equals(paramName)
325+
&& !TIMESTAMP.equals(paramName) && !SIGN.equals(paramName)) {
326+
params.put(paramName, paramValue);
327+
}
328+
}
329+
}
330+
}
331+
332+
return params;
333+
}
290334

291335
/**
292336
* Extract parameters from JSON request body
@@ -356,6 +400,74 @@ private static Map<String, String> extractJsonParams(HttpServletRequest request)
356400
return params;
357401
}
358402

403+
/**
404+
* Extract parameters from JSON request body without length filtering
405+
* Supports nested JSON structures through recursive flattening
406+
* This method is used for signature generation to support long parameters
407+
*
408+
* @param request the HTTP servlet request
409+
* @return map of parameters extracted from JSON body without length restrictions
410+
*/
411+
private static Map<String, String> extractJsonParamsWithoutLengthFilter(HttpServletRequest request) {
412+
Map<String, String> params = new HashMap<>();
413+
414+
try {
415+
String jsonBody = null;
416+
417+
// Check if request is already a cached wrapper
418+
if (request instanceof CachedBodyHttpServletRequest) {
419+
jsonBody = ((CachedBodyHttpServletRequest) request).getBody();
420+
} else {
421+
// Try to read from the request directly
422+
// This may fail if the stream has already been consumed
423+
try {
424+
StringBuilder sb = new StringBuilder();
425+
try (BufferedReader reader = request.getReader()) {
426+
String line;
427+
while ((line = reader.readLine()) != null) {
428+
sb.append(line);
429+
}
430+
}
431+
jsonBody = sb.toString();
432+
} catch (IllegalStateException e) {
433+
// getReader() has already been called, try to create a cached wrapper
434+
logger.warn("Request body has already been read, attempting to create cached wrapper");
435+
try {
436+
CachedBodyHttpServletRequest cachedRequest = new CachedBodyHttpServletRequest(request);
437+
jsonBody = cachedRequest.getBody();
438+
} catch (Exception ex) {
439+
logger.warn("Failed to create cached request wrapper: {}", ex.getMessage());
440+
return params; // Return empty params if we can't read the body
441+
}
442+
}
443+
}
444+
445+
if (jsonBody != null && !jsonBody.trim().isEmpty()) {
446+
try {
447+
JSONObject jsonObject = JSON.parseObject(jsonBody);
448+
// Use recursive flattening for better handling of nested structures
449+
Map<String, Object> flattenedParams = new HashMap<>();
450+
for (String key : jsonObject.keySet()) {
451+
Object value = jsonObject.get(key);
452+
processObject(flattenedParams, key, value);
453+
}
454+
455+
// Convert flattened object map to string map without length filtering
456+
for (Map.Entry<String, Object> entry : flattenedParams.entrySet()) {
457+
params.put(entry.getKey(), entry.getValue().toString());
458+
}
459+
} catch (Exception e) {
460+
logger.warn("Failed to parse JSON body: {}", e.getMessage());
461+
}
462+
}
463+
464+
} catch (Exception e) {
465+
logger.warn("Failed to extract JSON parameters: {}", e.getMessage());
466+
}
467+
468+
return params;
469+
}
470+
359471
/**
360472
* Recursively process object to flatten complex objects (Map and List) into flat key-value pairs
361473
* This approach provides better handling of nested structures compared to simple normalization

app/application/src/test/java/com/alipay/application/service/system/utils/OpenApiClientJavaDemo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ public static String queryScanResult(Object params)
211211
HttpClient client = HttpClient.newHttpClient();
212212
HttpRequest request = HttpRequest.newBuilder()
213213
.uri(URI.create(url))
214+
.header("version", "v2")
214215
.header("access-key", ACCESS_KEY)
215216
.header("timestamp", timestamp)
216217
.header("sign", signature)

0 commit comments

Comments
 (0)