wuyouzhuguli/SpringAll · error · ValidateCodeException
验证码不存在!
Error message
验证码不存在!
What it means
ValidateCodeException thrown when the SmsCode looked up from session under SESSION_KEY_SMS_CODE + mobileInRequest is null. IMPORTANT BUG: SmsCodeFilter (project 61) reads mobileInRequest from the 'smsCode' parameter (getStringParameter(..., "smsCode")) instead of 'mobile', so the session key becomes SESSION_KEY_SMS_CODE + <the sms code value>, which never matches the key ValidateController stored under (SESSION_KEY_SMS_CODE + mobile). This error is therefore triggered even with a valid mobile and code.
Source
Thrown at 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java:54
} catch (ValidateCodeException e) {
authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);
return;
}
}
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 the copy-paste bug: read 'mobile' for mobileInRequest so the session key matches ValidateController's storage key.
- After the fix, ensure GET /code/sms?mobile=<num> was called in the same session before login.
- Share the JSESSIONID cookie across both requests; in clusters use Spring Session.
Example fix
// before // String mobileInRequest = ServletRequestUtils.getStringParameter(req, "smsCode"); // after String mobileInRequest = ServletRequestUtils.getStringParameter(req, "mobile");
Defensive patterns
Strategy: try-catch
Validate before calling
// This is a server-side bug; client cannot fully avoid it. After patching the filter,
// ensure GET /code/sms?mobile=<num> ran in the same session before login.
await fetch(`/code/sms?mobile=${mobile}`, { credentials:'same-origin' }); Try / catch
// Patch the filter first, then this becomes a normal 'generate-then-login' flow.
// Server fix:
// String mobileInRequest = ServletRequestUtils.getStringParameter(req, "mobile");
try { await smsLogin(); } catch (e) { if (/不存在/.test(e.message)) await resendSms(); } Prevention
- Fix the copy-paste bug: read 'mobile' for the mobile param so the session key matches ValidateController.
- Ensure GET /code/sms?mobile=... is called before login in the same session.
- Share JSESSIONID across both requests; use Spring Session in clusters.
- Add a unit test asserting the lookup key equals SESSION_KEY_SMS_CODE + mobile.
When it happens
Trigger: Any /login/mobile request, because the lookup key is built from the wrong parameter. Also genuinely triggered when the SMS code was never created (no prior GET /code/sms?mobile=...) or the session expired.
Common situations: Always-on bug in this sample project; developers copying this filter verbatim hit '验证码不存在' on every SMS login; session cookie not shared between /code/sms and /login/mobile.
Related errors
AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14).
Data as JSON: /api/errors/24b9eb55eba60820.
Report an issue: GitHub.