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

能否在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:42:20