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
相关产品推荐
相关产品推荐

