{"record":{"id":"77dde61b67b0f0e4","repo":"elunez/eladmin","slug":"error-77dde6","errorCode":null,"errorMessage":"无效验证码","messagePattern":"无效验证码","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java","lineNumber":75,"sourceCode":"            String code = RandomUtil.randomNumbers (6);\n            // 存入缓存\n            if(!redisUtils.set(redisKey, code, expiration)){\n                throw new BadRequestException(\"服务异常，请联系网站负责人\");\n            }\n            content = template.render(Dict.create().set(\"code\",code));\n            // 存在就再次发送原来的验证码\n        } else {\n            content = template.render(Dict.create().set(\"code\",oldCode));\n        }\n        emailVo = new EmailVo(Collections.singletonList(email),\"ELADMIN后台管理系统\",content);\n        return emailVo;\n    }\n\n    @Override\n    public void validated(String key, String code) {\n        String value = redisUtils.get(key, String.class);\n        if(!code.equals(value)){\n            throw new BadRequestException(\"无效验证码\");\n        } else {\n            redisUtils.del(key);\n        }\n    }\n}\n","sourceCodeStart":57,"sourceCodeEnd":81,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java#L57-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nString value = redisUtils.get(key, String.class);\nif(!code.equals(value)){\n    throw new BadRequestException(\"无效验证码\");\n}\n\n// after: separate expired/missing from wrong code\nString value = redisUtils.get(key, String.class);\nif(value == null){\n    throw new BadRequestException(\"验证码已过期，请重新获取\");\n}\nif(!value.equals(code)){\n    throw new BadRequestException(\"验证码错误\");\n}","handlingStrategy":"validation","validationCode":"// before calling validated(), confirm a code still exists for this key\nString cached = redisUtils.get(key, String.class);\nif (cached == null) { requestNewCode(); return; }\nverifyService.validated(key, code);","typeGuard":null,"tryCatchPattern":"try { verify.validated(key, code.trim()); } catch (BadRequestException e) { // show 'wrong or expired code', keep the form open, allow resend after cooldown } }","preventionTips":["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."],"tags":["verification-code","redis","validation","email"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}