如何实现带邮箱验证码验证的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
相关产品推荐
相关产品推荐

