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

pyotp密钥复用问题:重置密码OTP验证过期异常及解决需求

问题解决方案

核心问题分析

你当前的问题根源在于:生成OTP时使用的随机secret没有持久化存储,重置密码时又重新生成了新的secret,导致TOTP验证时用了不同的密钥,自然会提示过期或无效。同时要实现每次请求接口都发新验证码,只需在每次请求时生成新的secret和验证码,覆盖用户旧的验证记录即可。

具体修改步骤

1. 更新VerificationCode模型

首先需要给VerificationCode模型添加一个secret字段,用于存储生成OTP时的密钥:

# 假设你的VerificationCode模型定义类似这样
class VerificationCode(Base):
    __tablename__ = "verification_codes"
    id = Column(Integer, primary_key=True, index=True)
    code = Column(String, nullable=False)
    secret = Column(String, nullable=False)  # 新增该字段用于存储OTP密钥
    user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
    user = relationship("User", back_populates="code")

2. 修改生成OTP验证码的方法

每次请求时生成新的secret和验证码,直接覆盖用户原有的验证记录(不管旧验证码是否仍有效):

secret = pyotp.random_base32()
totp = pyotp.TOTP(secret, interval=settings.verification_code_expire_time)
verification_code = totp.now()

if not user.code:
    # 用户无验证记录,创建新条目
    user.code = VerificationCode(code=verification_code, secret=secret)
else:
    # 覆盖旧的验证码和对应密钥
    user.code.code = verification_code
    user.code.secret = secret

await db.commit()
return verification_code

3. 修改重置密码的方法

从数据库中取出对应验证码绑定的secret,用这个密钥来验证OTP的有效性:

query = select(VerificationCode).where(VerificationCode.code == reset_password_schema.verification_code)
result = await db.execute(query)
verification_code = result.scalar_one_or_none()

if not verification_code:
    raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="无效的验证码。")

# 使用存储的密钥创建TOTP实例,而非生成新的随机密钥
totp = pyotp.TOTP(verification_code.secret, interval=settings.verification_code_expire_time)

if not totp.verify(reset_password_schema.verification_code):
    raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码已过期或无效。")

# 执行密码更新操作
query = (
    update(User).where(User.id == verification_code.user_id).values(
        password=reset_password_schema.new_password)
)
await db.execute(query)
await db.commit()

额外说明

  • 每次请求发送验证码接口时,都会生成全新的secret和验证码,直接覆盖用户旧的验证记录,满足“即使原验证码仍有效也发送新验证码”的需求。
  • TOTP的验证逻辑依赖生成验证码时的secret和当前时间窗口,使用同一密钥才能正确校验验证码是否在有效期内。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 19:25:08