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

  1. Confirm the same key construction (`key + email`) is used by both sendEmail and validated — mismatched prefixes are the most common cause.
  2. Check in Redis (KEYS / TTL on the key) whether the code still exists and how much TTL remains; re-send a code if expired.
  3. Trim and normalize (lowercase) the email on both request and validation paths.
  4. If the code was already used, request a new one — successful validation deletes the key.
  5. 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

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.