jeecgboot/JeecgBoot · error · IllegalArgumentException
Sign签名校验失败!
Error message
Sign签名校验失败!
What it means
This error is thrown when the actual signature verification fails — the X-SIGN header does not match the computed MD5 hash of the sorted request parameters concatenated with the signatureSecret. SignUtil.verifySign compares headerSign with getParamsSign(allParams), and if they differ, the request is rejected. This is the core cryptographic mismatch error.
Source
Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java:124
long currentTime = System.currentTimeMillis();
long timeDiff = currentTime - clientTimestamp;
long maxExpireMs = MAX_EXPIRE * length1000;
log.debug("时间戳验证(Unix): 时间差{}ms", timeDiff);
if (timeDiff > maxExpireMs) {
log.error("时间戳已过期: {}ms > {}ms", timeDiff, maxExpireMs);
throw new IllegalArgumentException("签名验证失败,请求时效性验证失败!");
}
}
//2.校验签名
boolean isSigned = SignUtil.verifySign(allParams,headerSign);
if (isSigned) {
log.debug("签名验证通过");
} else {
log.error("签名验证失败, 参数: {}", allParams);
throw new IllegalArgumentException("Sign签名校验失败!");
}
} catch (IllegalArgumentException e) {
// 重新抛出签名验证异常
throw e;
} catch (Exception e) {
// 包装其他异常(如IOException)
log.error("签名验证异常: {}", e.getMessage());
throw new IllegalArgumentException("Sign签名校验失败:" + e.getMessage());
}
}
}
View on GitHub (pinned to 96fb33f5ec)
Solutions
- Verify that the client uses the exact same jeecg.signatureSecret value configured in the server's application.yml.
- Ensure the client sorts all parameters alphabetically, serializes to JSON, appends the secret, then MD5-hashes and uppercases the result — matching SignUtil.getParamsSign().
- Confirm that the _t parameter is excluded from signing (SignUtil removes it at line 53) and that body parameters (from @RequestBody) are included.
- Enable debug logging (log.debug) on SignUtil and SignAuthInterceptor to compare the parameter maps and computed signs between client and server.
Example fix
// before (client) — wrong: signing raw params without JSON serialization
String sign = md5(params.toString() + secret);
// after — correct: match server's algorithm
TreeMap<String,String> sortedParams = new TreeMap<>(params);
sortedParams.remove("_t");
String jsonStr = JSON.toJSONString(sortedParams);
String sign = DigestUtils.md5DigestAsHex((jsonStr + secret).getBytes("UTF-8")).toUpperCase(); Defensive patterns
Strategy: validation
Validate before calling
// Client-side: replicate the exact server signing algorithm
public static String computeSign(SortedMap<String, String> params, String secret) {
params.remove("_t"); // server removes this
String jsonStr = com.alibaba.fastjson.JSON.toJSONString(params);
String raw = jsonStr + secret;
return org.springframework.util.DigestUtils
.md5DigestAsHex(raw.getBytes(java.nio.charset.StandardCharsets.UTF_8))
.toUpperCase();
} Type guard
// Verify sign matches before sending (self-check)
public static boolean verifySelfSign(SortedMap<String, String> params, String headerSign, String secret) {
if (params == null || headerSign == null || headerSign.isEmpty()) return false;
params.remove("_t");
String jsonStr = JSON.toJSONString(params);
String expected = DigestUtils.md5DigestAsHex((jsonStr + secret).getBytes(StandardCharsets.UTF_8)).toUpperCase();
return headerSign.equals(expected);
} Try / catch
try {
response = httpClient.execute(request);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Sign签名校验失败!")) {
log.error("Signature mismatch. Enable debug logging to compare param maps.");
// Do NOT retry with same signature — regenerate from scratch
}
throw e;
} Prevention
- Use the exact same JSON serializer (FastJSON) as the server — Gson/Jackson may order keys differently
- Ensure the signatureSecret is identical on client and server
- Include body parameters (from @RequestBody) in the parameter map, not just URL params
- Remove the _t parameter from signing on the client side
- Always uppercase the final MD5 hex string
When it happens
Trigger: A client sends a request with a valid X-TIMESTAMP (not expired) but the X-SIGN header value does not equal the MD5 of (JSON-sorted-params + signatureSecret). Common causes: wrong secret, wrong parameter serialization, parameters sent in a different format than expected, or the _t timestamp parameter not being removed from the signature computation.
Common situations: The jeecg.signatureSecret was changed on the server but the client still uses the old secret. The client serializes parameters differently (e.g., includes _t, uses different JSON field order, omits body parameters). A BodyReaderHttpServletRequestWrapper that failed to capture body params leads to an incomplete parameter map. URL path variables (x-path-variable) not included in the signature.
Related errors
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/1ce0e046f3c056bd.
Report an issue: GitHub.