能否在Django REST framework中通过OTP验证邮箱后完成用户注册?
用Django REST Framework实现分步邮箱验证式用户注册
完全可以用Django REST Framework(DRF)实现你描述的四步注册流程,核心思路是通过临时存储OTP和邮箱验证状态拆分注册环节,以下是具体实现方案:
1. 第一步:接收邮箱并发送OTP
先创建一个API接口,仅接收用户输入的邮箱,生成一次性验证码(OTP)并发送到该邮箱,同时临时存储OTP与邮箱的关联关系。
关键代码:
- 序列化器(仅验证邮箱格式):
from rest_framework import serializers from django.contrib.auth.models import User class EmailSerializer(serializers.Serializer): email = serializers.EmailField(required=True) def validate_email(self, value): # 可选:提前检查邮箱是否已注册 if User.objects.filter(email=value).exists(): raise serializers.ValidationError("该邮箱已绑定账户") return value
- 视图逻辑:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status import secrets from django.core.mail import send_mail from django.core.cache import cache class SendOTPView(APIView): def post(self, request): serializer = EmailSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] # 生成6位随机数字OTP otp = secrets.randbelow(900000) + 100000 # 缓存OTP,设置15分钟过期 cache.set(f"otp_{email}", otp, timeout=900) # 发送邮件(需提前在settings.py配置邮件后端) send_mail( '账户注册验证码', f'你的注册验证码为:{otp},15分钟内有效', 'noreply@example.com', [email], fail_silently=False, ) return Response({"message": "验证码已发送至你的邮箱"}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
2. 第二步:验证OTP
创建第二个API接口,接收邮箱和用户输入的OTP,验证匹配后标记该邮箱为已验证状态。
关键代码:
- 序列化器:
class OTPVerificationSerializer(serializers.Serializer): email = serializers.EmailField(required=True) otp = serializers.CharField(required=True, max_length=6, min_length=6)
- 视图逻辑:
class VerifyOTPView(APIView): def post(self, request): serializer = OTPVerificationSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] otp_input = serializer.validated_data['otp'] cached_otp = cache.get(f"otp_{email}") if cached_otp and str(cached_otp) == otp_input: # 标记邮箱已验证,缓存1小时(足够用户完成后续注册) cache.set(f"verified_email_{email}", True, timeout=3600) # 清理已使用的OTP缓存 cache.delete(f"otp_{email}") return Response({"message": "邮箱验证成功,请继续完成注册"}, status=status.HTTP_200_OK) return Response({"error": "验证码无效或已过期"}, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3. 第三步:填写用户名和密码完成注册
最后创建注册完成的API接口,仅允许已验证的邮箱提交用户名和密码信息,完成用户账户创建。
关键代码:
- 序列化器:
class CompleteRegistrationSerializer(serializers.ModelSerializer): password1 = serializers.CharField(write_only=True, required=True) password2 = serializers.CharField(write_only=True, required=True) class Meta: model = User fields = ['email', 'username', 'password1', 'password2'] def validate(self, attrs): # 验证两次密码一致 if attrs['password1'] != attrs['password2']: raise serializers.ValidationError("两次输入的密码不匹配") # 验证邮箱已完成OTP验证 email = attrs['email'] if not cache.get(f"verified_email_{email}"): raise serializers.ValidationError("邮箱未验证,请先完成验证码校验") # 可选:检查用户名是否已存在 if User.objects.filter(username=attrs['username']).exists(): raise serializers.ValidationError("该用户名已被使用") return attrs def create(self, validated_data): # 创建用户并设置密码 user = User.objects.create( email=validated_data['email'], username=validated_data['username'] ) user.set_password(validated_data['password1']) user.save() # 清理邮箱验证状态缓存 cache.delete(f"verified_email_{validated_data['email']}") return user
- 视图逻辑:
from rest_framework.generics import CreateAPIView class CompleteRegistrationView(CreateAPIView): serializer_class = CompleteRegistrationSerializer
额外注意事项
- 邮件配置:需在
settings.py中配置Django邮件后端(如SMTP服务),确保邮件能正常发送。 - 缓存选型:默认本地内存缓存仅适合开发环境,生产环境建议改用Redis等分布式缓存,避免多服务器部署时缓存不共享的问题。
- 安全优化:OTP使用
secrets模块生成随机值,避免可预测的验证码;合理设置缓存过期时间,平衡用户操作时长与安全风险。
内容的提问来源于stack exchange,提问作者Destiny Franks
相关产品推荐
相关产品推荐

