wuyouzhuguli/SpringAll · warning · ValidateCodeException

验证码已过期!

Error message

验证码已过期!

What it means

Thrown when ImageCode.isExpire() is true: LocalDateTime.now() is after the code's expireTime. ValidateController creates the code with a 60-second lifetime (expireIn=60). The filter removes the session attribute before throwing, so the code is single-use after expiry.

Source

Thrown at 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java:55

                return;
            }
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException {
        ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);
        String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode");

        if (StringUtils.isBlank(codeInRequest)) {
            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(), codeInRequest)) {
            throw new ValidateCodeException("验证码不正确!");
        }
        sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);

    }

}

View on GitHub (pinned to 614d2578d9)

Solutions

  1. Refresh the captcha image (GET /code/image) and resubmit a fresh code within 60 seconds.
  2. Increase expireIn in ValidateController.createImageCode (and the matching SmsCode lifetime) if users need more time.
  3. On the frontend, auto-refresh the captcha image when the user focuses the login form or after a failure.

Example fix

// before (ValidateController.createImageCode)
// int expireIn = 60; // 验证码有效时间 60s

// after
int expireIn = 300; // extend to 5 minutes
Defensive patterns

Strategy: retry

Validate before calling

// Track when the captcha was fetched; refresh if older than 50s (TTL is 60s).
let captchaFetchedAt = 0;
async function ensureFreshCaptcha() {
  if (Date.now() - captchaFetchedAt > 50_000) { await refreshCaptcha(); }
}

Try / catch

try { await login(); }
catch (e) {
  if (/已过期/.test(e.message)) { await refreshCaptcha(); /* user re-enters */ }
  else handleError(e);
}

Prevention

When it happens

Trigger: More than 60 seconds elapsed between GET /code/image and the login POST; the user lingered on the form or typed slowly; client clock vs the generated code's plusSeconds(60) window was exceeded.

Common situations: Default 60s expiry is too short for slow users; user refreshed only the form (not the image) and submitted a stale code; debugging paused between fetch and submit.

Related errors


AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14). Data as JSON: /api/errors/3e673ca9bd9df465. Report an issue: GitHub.