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

如何实现带邮箱验证码验证的Django及DRF用户注册功能

DRF实现邮箱验证码注册流程

核心流程梳理

  • 用户提交邮箱、用户名、密码到发送验证码接口,后端暂不创建用户
  • 后端生成6位随机验证码,将验证码与用户注册信息关联存储(推荐用Redis并设置5分钟过期时间)
  • 调用邮件服务向用户邮箱发送验证码
  • 用户收到验证码后,提交验证码到验证注册接口
  • 后端校验验证码有效性,验证通过则创建用户并返回成功,失败则返回对应错误提示

环境依赖准备

需要安装以下依赖包:

pip install djangorestframework django-redis

配置文件修改

在settings.py中配置邮件服务和Redis缓存:

# 邮件配置(以QQ邮箱为例,替换为你的SMTP服务信息)
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@qq.com'
EMAIL_HOST_PASSWORD = 'your-app-authorization-code'  # 注意是邮箱授权码而非登录密码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

# Redis缓存配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

序列化器编写

注册请求序列化器(校验用户输入)

# serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User

class RegisterRequestSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    username = serializers.CharField(max_length=150, required=True)
    password = serializers.CharField(min_length=6, write_only=True, required=True)

    def validate_username(self, value):
        if User.objects.filter(username=value).exists():
            raise serializers.ValidationError("用户名已存在")
        return value

    def validate_email(self, value):
        if User.objects.filter(email=value).exists():
            raise serializers.ValidationError("邮箱已被注册")
        return value

验证码验证序列化器

class VerifyCodeSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    code = serializers.CharField(max_length=6, min_length=6, required=True)

视图实现

发送验证码接口

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.core.cache import cache
from django.core.mail import send_mail
import random
from .serializers import RegisterRequestSerializer

class SendVerificationCodeView(APIView):
    def post(self, request):
        serializer = RegisterRequestSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            username = serializer.validated_data['username']
            password = serializer.validated_data['password']
            
            # 生成6位随机验证码
            code = ''.join(random.choices('0123456789', k=6))
            # 缓存注册信息与验证码,5分钟后过期
            cache_key = f'register_{email}'
            cache.set(cache_key, {
                'username': username,
                'password': password,
                'code': code
            }, timeout=300)
            
            # 发送验证码邮件
            subject = '注册验证码'
            message = f'你的注册验证码是:{code},请在5分钟内完成验证。'
            send_mail(subject, message, None, [email])
            
            return Response({'msg': '验证码已发送至你的邮箱'}, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

验证验证码并创建用户接口

from django.contrib.auth.models import User
from .serializers import VerifyCodeSerializer

class VerifyCodeAndRegisterView(APIView):
    def post(self, request):
        serializer = VerifyCodeSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            code = serializer.validated_data['code']
            
            cache_key = f'register_{email}'
            cached_data = cache.get(cache_key)
            if not cached_data:
                return Response({'msg': '验证码已过期或无效'}, status=status.HTTP_400_BAD_REQUEST)
            
            if cached_data['code'] != code:
                return Response({'msg': '验证码错误'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 验证通过,创建用户
            user = User.objects.create_user(
                username=cached_data['username'],
                email=email,
                password=cached_data['password']
            )
            # 删除缓存的注册数据,避免重复使用
            cache.delete(cache_key)
            
            return Response({'msg': '注册成功', 'user_id': user.id}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

路由配置

# urls.py
from django.urls import path
from .views import SendVerificationCodeView, VerifyCodeAndRegisterView

urlpatterns = [
    path('send-code/', SendVerificationCodeView.as_view(), name='send-verification-code'),
    path('verify-register/', VerifyCodeAndRegisterView.as_view(), name='verify-and-register'),
]

额外优化建议

  • 限制同一邮箱的验证码发送频率,比如1分钟内仅允许发送一次,可通过缓存存储发送时间实现
  • 邮件内容可改用HTML格式提升可读性,使用send_mail方法的html_message参数
  • 生产环境建议用异步任务(如Celery)发送邮件,避免接口因等待邮件发送而响应缓慢
  • 可增加验证码错误次数限制,防止暴力破解

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:33:22