You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot实现OTP校验始终提示无效OTP报错如何解决

问题说明

我开发了一套用户注册登录系统:用户先完成注册,再使用注册时填写的邮箱和密码登录,登录成功后系统会生成随机字符串作为OTP(一次性验证码)发送至用户邮箱,同时将该OTP存储到数据库中。目前需要实现OTP校验逻辑,比对用户输入的OTP与数据库中存储的OTP是否一致,确认用户输入正确性,但编写完对应逻辑后,每次校验都会提示OTP无效。

相关代码

OTPMailContoller 类

@PostMapping("/validate-otp")
public SessionHandling validateOtp(@RequestBody SessionHandling otp) throws Exception{

    String tempOtp = otp.getOneTimePassword();

    SessionHandling UserOtp = null;

    if(tempOtp != null) {
        UserOtp = emailService.fetchUserByOneTimePassword(tempOtp);
    }
    if(UserOtp == null){
        throw new Exception("invalid otp !!!");
    }
    return UserOtp;
}

Service 类

public SessionHandling fetchUserByOneTimePassword(String tempOtp) {
    return repo.findByOneTimePassword(tempOtp);
}

Repository 类

@Query(value = "select * from session_handling where one_time_password= :otp", nativeQuery =true)
public SessionHandling findByOneTimePassword(@Param("otp")String tempOtp);

Model 类

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String email;
private String password;
private String cpassword;

private static final long OTP_VALID_DURATION = 5 * 60 * 1000;   // 5分钟有效期

@Column(name = "one_time_password")
private String oneTimePassword;

报错信息

Invalid otp !!!

问题排查与修复方案

每次都触发OTP无效报错,核心是findByOneTimePassword查询返回了null,按优先级排查以下问题:

  • OTP生成后未持久化到数据库
    这是最高发的原因:生成OTP、给对象setOneTimePassword、发送邮件后,没有调用repo.save()方法把更新后的对象存入数据库,导致数据库中对应记录的one_time_password字段为null,查询时自然匹配不到结果。
    修复:生成OTP后必须调用持久化方法存库,发送邮件的逻辑要放在存库成功之后。

  • 前端传参字段不匹配,后端拿不到OTP值
    Spring Boot默认按驼峰命名规则解析JSON参数,如果前端传的参数字段是下划线命名one_time_password,而实体类字段是驼峰oneTimePassword,且没有配置全局下划线转驼峰、也没有加@JsonProperty("one_time_password")注解,otp.getOneTimePassword()拿到的就是null,根本不会执行数据库查询。
    排查方式:在controller里加一行日志打印tempOtp的值,看是不是null。如果是null就调整参数映射规则。

  • OTP存储/传入时存在格式不一致问题
    检查生成OTP后存库时,是否做了多余的处理:比如全大/小写转换、拼接了多余字符、前后带空格/换行符;另外检查用户输入的OTP是否做了多余的trim处理,导致和库中存储的值不一致。

  • 现有逻辑的设计缺陷(修复完上述问题后必须调整)

    • 不能只靠OTP单字段查询:必须带上当前用户的唯一标识(邮箱/用户ID)作为查询条件,避免OTP碰撞导致的越权问题,也能避免多个用户生成相同OTP时匹配到错误记录。
    • 你在实体类里定义了5分钟的OTP有效期,但现有逻辑完全没做过期校验,需要给表加OTP生成时间字段,查询时同时判断OTP是否在有效期内,过期的OTP直接判定无效。

    调整后的Repository查询示例:

    @Query(value = "select * from session_handling where email = :email and one_time_password= :otp and otp_generate_time > :expireTime", nativeQuery =true)
    public SessionHandling findValidOtp(@Param("email")String email, @Param("otp")String otp, @Param("expireTime")LocalDateTime expireTime);
    

内容的提问来源于stack exchange,提问作者Harshit Toxia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:39:20