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

Django中OTP的短信/邮件发送及验证(含过期判断)问题求助

Django双因素认证(2FA)验证问题解决方案

核心问题分析

你的代码存在两个关键错误导致验证失效:

  • 错误存储了当前OTP值而非TOTP依赖的base32共享密钥,TOTP的验证逻辑是基于密钥实时计算时间步对应的OTP,而非直接比对存储的静态OTP。
  • 验证时未使用用户对应的密钥生成TOTP实例,导致验证逻辑完全不匹配。

修正步骤

1. 更新用户模型

首先给用户模型添加存储base32密钥的字段:

# models.py
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    is_verified = models.BooleanField(default=False)
    otp_secret = models.CharField(max_length=32, blank=True, null=True)  # 新增字段

执行迁移命令:

python manage.py makemigrations
python manage.py migrate

2. 修正OTP生成代码

生成密钥并保存到用户,不需要存储当前OTP:

import pyotp

# 生成base32密钥并关联到用户
user.otp_secret = pyotp.random_base32()
user.save()

# 生成当前OTP(用于发送给用户,比如短信/邮件)
totp = pyotp.TOTP(user.otp_secret)
current_otp = totp.now()
# 这里可以将current_otp发送给用户,无需存入数据库

3. 修正OTP验证代码

使用用户存储的密钥生成TOTP实例,同时通过window参数控制过期时间:

# 获取用户提交的OTP(从请求中获取)
submitted_otp = request.POST.get('otp')

# 用用户的密钥创建TOTP实例
totp = pyotp.TOTP(user.otp_secret)

# 验证OTP:window=1表示允许前后各1个时间步(每个时间步默认30秒,即总有效期60秒)
# verify方法返回True表示验证通过,False则为过期或错误
if totp.verify(submitted_otp, window=1):
    user.is_verified = True
    user.save()
    # 验证通过后的逻辑(比如登录)
else:
    # 处理OTP错误/过期的情况(返回提示)
    pass

关键说明

  • TOTP默认时间步为30秒,window=N表示允许验证当前时间步前后N个时间步的OTP,以此控制过期时长。
  • 永远不要存储静态OTP值到数据库,因为OTP是随时间动态变化的,验证时必须用密钥实时计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 03:20:27