wuyouzhuguli/SpringAll · warning · Exception
验证码已过期!
Error message
验证码已过期!
What it means
A plain java.lang.Exception '验证码已过期!' (verification code expired) is thrown by SmsCodeFilter.validateCode when redisCodeService.get(...) returns null for the given mobile. The SMS code is stored in Redis with a TTL keyed by mobile number; a null means no code exists under that key. This gate runs before the SMS authentication provider.
Source
Thrown at 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsCodeFilter.java:52
} catch (Exception e) {
authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, new AuthenticationServiceException(e.getMessage()));
return;
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private void validateCode(ServletWebRequest servletWebRequest) throws Exception {
String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode");
String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "mobile");
String codeInRedis = redisCodeService.get(servletWebRequest, mobileInRequest);
if (StringUtils.isBlank(smsCodeInRequest)) {
throw new Exception("验证码不能为空!");
}
if (codeInRedis == null) {
throw new Exception("验证码已过期!");
}
if (!StringUtils.equalsIgnoreCase(codeInRedis, smsCodeInRequest)) {
throw new Exception("验证码不正确!");
}
redisCodeService.remove(servletWebRequest, mobileInRequest);
}
}View on GitHub (pinned to 614d2578d9)
Solutions
- Request a fresh SMS code (re-trigger the send-code endpoint) and submit login within the configured TTL window.
- Verify redisCodeService uses an identical key (same mobile normalization and prefix) for both set (on send) and get (on validate), and that the TTL on set is non-zero.
- Confirm validateCode's remove() is only called after a successful match, so legitimate first attempts are not prematurely invalidated.
- Check Redis connectivity and that keys survive across requests (no flush, correct DB index, persistent rather than in-memory config in tests).
- Make the code's expiry window explicit to the user (countdown UI) so submissions land inside the TTL.
Example fix
// before
if (codeInRedis == null) {
throw new Exception("验证码已过期!");
}
// after — typed exception + distinguish never-issued vs expired
if (codeInRedis == null) {
throw new ValidateCodeException("验证码已过期或未发送,请重新获取");
} Defensive patterns
Strategy: validation
Validate before calling
// Check existence in Redis before delegating to the throwing filter
boolean codeAlive = redisCodeService.get(new ServletWebRequest(request), mobile) != null;
if (!codeAlive) {
return "验证码已失效,请重新获取";
} Type guard
private boolean codeStillValid(ServletWebRequest req, String mobile) {
return redisCodeService.get(req, mobile) != null;
} Try / catch
try {
filterChain.doFilter(request, response);
} catch (Exception e) {
if ("验证码已过期!".equals(e.getMessage())) {
response.setStatus(400);
response.getWriter().write("验证码已过期,请重新获取");
} else {
throw e;
}
} Prevention
- Send the SMS code and submit login promptly within the configured TTL.
- Use an identical Redis key (same mobile normalization and prefix) for set and get; verify with a KEYS/SCAN in dev.
- Only remove the code after a successful match — never before — to avoid premature invalidation.
- Confirm Redis persistence/connectivity so codes are not lost between requests in tests.
When it happens
Trigger: The SMS code's Redis TTL elapsed before login was attempted; the code was already consumed by a successful prior validate (validateCode calls redisCodeService.remove after a match, so resubmission hits null); the code was never generated/sent for that mobile; or Redis was flushed/restarted losing the key.
Common situations: User waited longer than the configured code validity window (often 60–300s) before submitting; double-submit of the login form after a first success (remove-on-success deletes the key); the SMS-send endpoint and the validate endpoint key the code differently (different mobile normalization or key prefix); or the Redis connection/serialization changed so get returns null for a key that was written by a prior deploy.
Related errors
AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14).
Data as JSON: /api/errors/b1ecf741d713980f.
Report an issue: GitHub.