elunez/eladmin · warning · BadRequestException

验证码错误

Error message

验证码错误

What it means

After confirming a captcha exists in Redis, AuthController.login compares it case-insensitively (equalsIgnoreCase) with the submitted code; blank submission or any mismatch (beyond case) throws '验证码错误'. The stored code is already deleted at this point, so the user must refresh the captcha and retry.

Source

Thrown at eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthController.java:91

    private final CaptchaConfig captchaConfig;
    private final PasswordEncoder passwordEncoder;
    private final UserDetailsServiceImpl userDetailsService;

    @Log("用户登录")
    @ApiOperation("登录授权")
    @AnonymousPostMapping(value = "/login")
    public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
        // 密码解密
        String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
        // 查询验证码
        String code = redisUtils.get(authUser.getUuid(), String.class);
        // 清除验证码
        redisUtils.del(authUser.getUuid());
        if (StringUtils.isBlank(code)) {
            throw new BadRequestException("验证码不存在或已过期");
        }
        if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
            throw new BadRequestException("验证码错误");
        }
        // 获取用户信息
        JwtUserDto jwtUser = userDetailsService.loadUserByUsername(authUser.getUsername());
        // 验证用户密码
        if (!passwordEncoder.matches(password, jwtUser.getPassword())) {
            throw new BadRequestException("登录密码错误");
        }
        Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成令牌
        String token = tokenProvider.createToken(jwtUser);
        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", properties.getTokenStartWith() + token);
            put("user", jwtUser);
        }};
        if (loginProperties.isSingleLogin()) {
            // 踢掉之前已经登录的token

View on GitHub (pinned to 55fbf70595)

Solutions

  1. Enter exactly the captcha answer: for arith type the RESULT of the math expression, matching characters for chinese types (case-insensitive for letters).
  2. If unsure or after any failed login, click the captcha image to refresh and re-enter.
  3. Frontend: send code.trim() and re-fetch captcha whenever a new uuid is issued.
Defensive patterns

Strategy: validation

Validate before calling

// frontend: trim and require non-empty code, and re-read arith captchas as results
const code = this.code.trim();
if (!code) { toast('请输入验证码'); return; }
submitLogin({ ...form, code });

Try / catch

try { await login(payload); } catch (e) { if (e.message.includes('验证码错误')) { await refreshCaptcha(); toast('验证码不正确,已刷新,请重试'); return; } throw e; }

Prevention

When it happens

Trigger: POST /auth/login where authUser.code differs from the Redis-stored value: misreading arith captcha answers (e.g. '3+2=?' answered as the expression), misreading chinese/gif characters, or the frontend sending the wrong field/whitespace.

Common situations: Arithmetic captcha misunderstanding — users sometimes type the whole equation instead of the result; case differences are fine but character errors are not; frontend trimming/encoding issues; user resubmitting a previously typed code after the uuid was refreshed (mismatch against the NEW code).

Related errors


AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14). Data as JSON: /api/errors/0d0514352b61a868. Report an issue: GitHub.