wuyouzhuguli/SpringAll · error · ValidateCodeException
验证码已过期!
Error message
验证码已过期!
What it means
ValidateCodeException thrown by SmsCodeFilter.validateCode() when the session SmsCode is present but expired (isExpire() true). NOTE: the expiry-cleanup path has a copy-paste defect - line 57 removes ValidateController.SESSION_KEY_IMAGE_CODE (the image-captcha key) instead of SESSION_KEY_SMS_CODE + mobileInRequest, so it neither clears the expired SMS code nor leaves the image session intact. Combined with the line-46 bug, the lookup key itself is often wrong.
Source
Thrown at 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java:58
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException {
String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode");
String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode");
SmsCode codeInSession = (SmsCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest);
if (StringUtils.isBlank(smsCodeInRequest)) {
throw new ValidateCodeException("验证码不能为空!");
}
if (codeInSession == null) {
throw new ValidateCodeException("验证码不存在!");
}
if (codeInSession.isExpire()) {
sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);
throw new ValidateCodeException("验证码已过期!");
}
if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), smsCodeInRequest)) {
throw new ValidateCodeException("验证码不正确!");
}
sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);
}
}View on GitHub (pinned to 614d2578d9)
Solutions
- Fix line 57 to remove ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest, not SESSION_KEY_IMAGE_CODE.
- Also fix line 46 so mobileInRequest is read from the 'mobile' parameter.
- Refresh the SMS code and resubmit within the TTL.
- Increase expireIn if legitimate users cannot submit in time.
Example fix
// before (line 57) sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); // after sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest);
Defensive patterns
Strategy: retry
Validate before calling
// client-side: refresh the SMS code and track its lifetime
async function refreshSmsCode(mobile) {
await fetch('/code/sms?mobile=' + encodeURIComponent(mobile), { credentials: 'same-origin' });
smsGeneratedAt = Date.now();
}
if (Date.now() - smsGeneratedAt > SMS_TTL_MS) await refreshSmsCode(mobile); Prevention
- Fix SmsCodeFilter line 57 to remove SESSION_KEY_SMS_CODE + mobileInRequest, not the image-captcha key.
- Also fix line 46 so the correct mobile is used to build the session key.
- Refresh the SMS code and resubmit within its TTL.
When it happens
Trigger: POST to /login/mobile with an SMS code whose age exceeds the configured expireIn; effectively reachable only after the line-46 mobile bug is fixed so the correct session key is consulted.
Common situations: User let the SMS code expire before submitting; expireIn configured too short; the wrong session attribute is being cleared (line 57 bug), leaving stale codes; mobile-key bug masks this branch entirely.
Related errors
AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14).
Data as JSON: /api/errors/3561afeb520bdc49.
Report an issue: GitHub.