Django创建账户时要求邮箱验证的实现方案咨询
我有一个Django项目,需要用户创建账户以访问内容,目前使用UserCreationForm实现注册功能。我的views.py代码如下:
def register_user(request): if request.method == "POST": user_form = UserCreationForm(request.POST) if user_form.is_valid(): new_user = user_form.save(commit=False) new_user.set_password(user_form.cleaned_data["password1"]) new_user.save() template = "account/registration/registration_done.html" context = {"new_user": new_user} else: # TODO: Handle exception raise BaseException elif request.method == "GET": user_form = UserCreationForm() template = "account/registration/register.html" context = {"user_form": user_form} else: raise NotImplementedError return render(request, template, context=context)
对应的模板代码为:
{% extends "base.html" %} {% block title %}Create an Account{% endblock %} {% block content %} <h1>Create an Account</h1> <form action="." method="post"> {{ user_form.as_p }} {% csrf_token %} <p><input type="submit" value="Create my account"></p> </form> {% endblock %}
当前功能可正常运行,但注册表单仅包含用户名、密码及密码确认字段,未要求用户输入有效邮箱。我希望添加必填邮箱字段,并发送邮件验证邮箱有效性及用户使用权,请问Django认证系统是否已有现成实现方案,还是需要自行编写表单及相关处理逻辑?
好问题!Django本身提供了基础支持,但完整的邮箱验证流程需要补充部分逻辑;你也可以用成熟的第三方库快速实现,下面分两种情况详细说明:
方案一:基于Django原生工具自行实现
Django默认的User模型本身就带有email字段,只是UserCreationForm没把它加入表单。我们可以自定义表单添加邮箱字段,再补充验证流程:
1. 自定义注册表单
在你的app里新建forms.py,继承UserCreationForm并添加必填邮箱字段:
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django import forms class CustomUserCreationForm(UserCreationForm): email = forms.EmailField(required=True, help_text='必填项,请输入有效的邮箱地址。') class Meta: model = User fields = ('username', 'email', 'password1', 'password2')
2. 更新视图逻辑
修改register_user视图,用自定义表单替代原有的UserCreationForm,同时将用户设置为未激活状态(等邮箱验证后再激活):
def register_user(request): if request.method == "POST": user_form = CustomUserCreationForm(request.POST) if user_form.is_valid(): new_user = user_form.save(commit=False) new_user.email = user_form.cleaned_data['email'] new_user.set_password(user_form.cleaned_data["password1"]) # 先设为未激活,验证邮箱后再激活账号 new_user.is_active = False new_user.save() # 后续添加生成验证token和发送邮件的逻辑 template = "account/registration/registration_done.html" context = {"new_user": new_user, "message": "请检查你的邮箱,点击激活链接完成注册"} else: # 替换抛异常逻辑,将表单错误返回给用户 template = "account/registration/register.html" context = {"user_form": user_form} elif request.method == "GET": user_form = CustomUserCreationForm() template = "account/registration/register.html" context = {"user_form": user_form} else: raise NotImplementedError return render(request, template, context=context)
3. 实现邮箱验证逻辑
Django自带的PasswordResetTokenGenerator可以复用,用来生成安全的邮箱验证token:
第一步:创建token生成器
在app里新建tokens.py:
from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.utils import six class AccountActivationTokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): # 用用户ID、时间戳和激活状态生成唯一哈希值 return ( six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active) ) account_activation_token = AccountActivationTokenGenerator()
第二步:发送验证邮件
回到视图,在new_user.save()后添加发送邮件的代码:
from django.core.mail import send_mail from django.urls import reverse from django.utils.http import urlsafe_base64_encode from django.utils.encoding import force_bytes from .tokens import account_activation_token # 生成激活链接 activate_url = request.build_absolute_uri( reverse("activate", kwargs={"uidb64": urlsafe_base64_encode(force_bytes(new_user.pk)), "token": account_activation_token.make_token(new_user)})) subject = '请激活你的账号' message = f'你好,{new_user.username}!请点击下面的链接激活你的账号:\n{activate_url}' # 替换为你的发件邮箱 send_mail(subject, message, 'your-email@example.com', [new_user.email])
第三步:创建激活视图
在views.py里添加激活账号的视图:
from django.utils.http import urlsafe_base64_decode from django.utils.encoding import force_text from django.contrib.auth.models import User from django.shortcuts import render, redirect from .tokens import account_activation_token def activate(request, uidb64, token): try: # 解码用户ID uid = force_text(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except(TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user is not None and account_activation_token.check_token(user, token): # 验证成功,激活用户 user.is_active = True user.save() return redirect('login') # 跳转到登录页 else: # 验证失败,返回错误页面 return render(request, 'account/registration/activation_invalid.html')
第四步:添加激活路由
在项目的urls.py里添加激活链接的路由:
from django.urls import path from . import views urlpatterns = [ # ... 其他路由 path('register/', views.register_user, name='register'), path('activate/<uidb64>/<token>/', views.activate, name='activate'), ]
方案二:使用第三方库快速实现(推荐)
如果不想自己编写大量逻辑,推荐使用django-allauth这个成熟的库,它内置了邮箱注册、邮箱验证、社交登录等全套功能,配置简单:
1. 安装库
pip install django-allauth
2. 配置settings.py
在INSTALLED_APPS和相关配置中添加:
INSTALLED_APPS = [ # ... 你的其他app 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', ] AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] SITE_ID = 1 # allauth必须配置此项 # 邮箱验证相关配置 ACCOUNT_EMAIL_REQUIRED = True # 注册时必须填写邮箱 ACCOUNT_AUTHENTICATION_METHOD = 'email' # 支持用邮箱登录 ACCOUNT_EMAIL_VERIFICATION = 'mandatory' # 强制验证邮箱后才能登录 ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 3 # 验证链接3天内有效
3. 添加路由
在项目的urls.py里添加allauth的路由:
from django.urls import path, include urlpatterns = [ # ... 其他路由 path('accounts/', include('allauth.urls')), ]
配置完成后,allauth会自动处理注册时的邮箱必填、发送验证邮件、激活账号等流程,你只需创建对应模板(或直接使用默认模板)即可,省去大量自定义逻辑的工作。
内容的提问来源于stack exchange,提问作者Batman

