elunez/eladmin · warning · BadRequestException
无效验证码
Error message
无效验证码
What it means
Thrown by VerifyServiceImpl.validated(key, code) when the user-submitted code does not string-equal the value stored in Redis under the same key. Note code.equals(value) is called on the request parameter, so a null Redis value (expired or never sent) also fails the check. On success the key is deleted so the code is single-use.
Source
Thrown at eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java:75
String code = RandomUtil.randomNumbers (6);
// 存入缓存
if(!redisUtils.set(redisKey, code, expiration)){
throw new BadRequestException("服务异常,请联系网站负责人");
}
content = template.render(Dict.create().set("code",code));
// 存在就再次发送原来的验证码
} else {
content = template.render(Dict.create().set("code",oldCode));
}
emailVo = new EmailVo(Collections.singletonList(email),"ELADMIN后台管理系统",content);
return emailVo;
}
@Override
public void validated(String key, String code) {
String value = redisUtils.get(key, String.class);
if(!code.equals(value)){
throw new BadRequestException("无效验证码");
} else {
redisUtils.del(key);
}
}
}
View on GitHub (pinned to 55fbf70595)
Solutions
- Confirm the same key construction (`key + email`) is used by both sendEmail and validated — mismatched prefixes are the most common cause.
- Check in Redis (KEYS / TTL on the key) whether the code still exists and how much TTL remains; re-send a code if expired.
- Trim and normalize (lowercase) the email on both request and validation paths.
- If the code was already used, request a new one — successful validation deletes the key.
- For clearer UX, distinguish 'expired' from 'wrong' by checking value == null separately before comparing.
Example fix
// before
String value = redisUtils.get(key, String.class);
if(!code.equals(value)){
throw new BadRequestException("无效验证码");
}
// after: separate expired/missing from wrong code
String value = redisUtils.get(key, String.class);
if(value == null){
throw new BadRequestException("验证码已过期,请重新获取");
}
if(!value.equals(code)){
throw new BadRequestException("验证码错误");
} Defensive patterns
Strategy: validation
Validate before calling
// before calling validated(), confirm a code still exists for this key
String cached = redisUtils.get(key, String.class);
if (cached == null) { requestNewCode(); return; }
verifyService.validated(key, code); Try / catch
try { verify.validated(key, code.trim()); } catch (BadRequestException e) { // show 'wrong or expired code', keep the form open, allow resend after cooldown } } Prevention
- Send the code request and the validation with the identical key + email string (normalize email to lowercase/trim).
- Start the UI countdown timer from the same expiration used server-side so users resubmit before expiry.
- Treat a failed validation as non-destructive: only resending/成功 deletes the key.
When it happens
Trigger: POST to the reset-password (or similar) endpoint that calls verify.validated(key, code) where: the code is wrong; the code expired (Redis TTL lapsed, value null); the key prefix differs from the one used at send time (key + email mismatch); or the code was already consumed (deleted) by an earlier successful validation.
Common situations: User types the code after it expired; frontend sends a different key/email combination than the one used when requesting the code; double submit of the same code (second call finds nothing in Redis); case/whitespace differences in the email used to build the key.
Related errors
AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14).
Data as JSON: /api/errors/77dde61b67b0f0e4.
Report an issue: GitHub.