Django内置的用户认证系统提供了完整的密码重置功能,默认流程会通过邮件将重置链接发送给用户,但在实际业务中,我们可能需要替换邮件通知为短信、站内信等其他方式,此时就需要禁用默认的自动邮件发送机制,自定义整个密码重置流程。

Django默认密码重置流程的核心逻辑
Django的密码重置功能主要由以下几个核心组件构成:
- PasswordResetView:处理密码重置请求,验证用户邮箱后触发邮件发送
- PasswordResetForm:负责收集用户邮箱、验证用户存在性,并调用邮件发送逻辑
- send_mail:Django内置的邮件发送函数,默认被PasswordResetForm调用
- PasswordResetDoneView:邮件发送完成后的提示页面
- PasswordResetConfirmView:处理用户点击重置链接后的密码修改逻辑
- PasswordResetCompleteView:密码修改完成后的提示页面
默认的邮件发送动作发生在PasswordResetForm的save方法中,该方法会调用send_mail函数将重置链接发送到用户邮箱,这就是我们需要拦截的核心位置。
禁用自动邮件发送的实现步骤
第一步:自定义密码重置表单,重写save方法
我们继承Django内置的PasswordResetForm,重写save方法,去掉其中的邮件发送逻辑,同时保留用户token生成等核心功能。
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
class CustomPasswordResetForm(PasswordResetForm):
def save(self, domain_override=None,
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.html',
use_https=False, token_generator=default_token_generator,
from_email=None, request=None, html_email_template_name=None,
extra_email_context=None):
# 获取当前站点信息
site = get_current_site(request)
# 遍历所有符合条件的用户
for user in self.get_users(self.cleaned_data["email"]):
# 生成用户重置密码的token和uid
uid = urlsafe_base64_encode(force_bytes(user.pk))
token = token_generator.make_token(user)
# 这里可以自定义通知逻辑,比如存储重置链接到数据库、调用短信接口等
# 示例:将重置链接存入用户扩展字段(实际根据业务调整)
reset_url = f"{'https' if use_https else 'http'}://{site.domain}/reset/{uid}/{token}/"
# 假设用户模型有reset_link字段存储临时重置链接
if hasattr(user, 'reset_link'):
user.reset_link = reset_url
user.save(update_fields=['reset_link'])
# 不调用父类的save方法,避免触发邮件发送
# 如果需要保留部分父类逻辑,也可以只注释掉邮件发送相关代码
# 父类save方法核心逻辑就是生成token和发送邮件,我们这里已经生成了token,所以不需要调用父类方法
第二步:自定义密码重置视图,使用自定义表单
重写PasswordResetView,将默认的表单替换为我们的自定义表单。
from django.contrib.auth.views import PasswordResetView
from .forms import CustomPasswordResetForm
class CustomPasswordResetView(PasswordResetView):
form_class = CustomPasswordResetForm
template_name = 'registration/password_reset_form.html'
success_url = '/reset/done/' # 自定义重置请求提交后的跳转地址
# 如果需要完全禁用邮件相关配置,也可以设置email_template_name为空,这里已经不需要了
# email_template_name = None
第三步:调整URL配置,使用自定义视图
在项目的urls.py中,将默认的密码重置路由替换为我们的自定义视图。
from django.urls import path
from .views import CustomPasswordResetView, CustomPasswordResetDoneView
urlpatterns = [
# 替换默认的密码重置路由
path('reset/password/', CustomPasswordResetView.as_view(), name='password_reset'),
# 重置请求提交后的提示页面,也可以自定义
path('reset/done/', CustomPasswordResetDoneView.as_view(), name='password_reset_done'),
# 其他密码重置相关路由(确认、完成页面)可以根据需要是否自定义,核心邮件发送逻辑已经在请求阶段禁用
]
第四步:自定义重置通知逻辑(可选)
如果需要将重置链接通知给用户,可以在自定义表单的save方法中添加对应的逻辑,比如调用短信接口:
import requests
class CustomPasswordResetForm(PasswordResetForm):
def save(self, domain_override=None,
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.html',
use_https=False, token_generator=default_token_generator,
from_email=None, request=None, html_email_template_name=None,
extra_email_context=None):
site = get_current_site(request)
for user in self.get_users(self.cleaned_data["email"]):
uid = urlsafe_base64_encode(force_bytes(user.pk))
token = token_generator.make_token(user)
reset_url = f"{'https' if use_https else 'http'}://{site.domain}/reset/{uid}/{token}/"
# 调用短信接口发送重置链接(示例,实际替换为自己的接口)
if hasattr(user, 'phone'):
sms_url = f"https://ipipp.com/sms/send"
params = {
"phone": user.phone,
"content": f"您的密码重置链接为:{reset_url},有效期为24小时"
}
requests.post(sms_url, json=params)
验证禁用效果
完成以上配置后,访问密码重置页面,输入已注册的用户邮箱提交请求,此时:
- 不会触发任何邮件发送动作
- 用户模型的自定义字段(如reset_link)会存储生成的重置链接
- 如果配置了短信通知,用户会收到对应的短信提醒
- 用户仍然可以通过生成的重置链接正常修改密码,因为
PasswordResetConfirmView的验证逻辑不依赖邮件发送,只需要正确的uid和token即可
注意事项
1. 禁用邮件发送后,需要确保有其他可靠的方式将重置链接通知到用户,否则用户无法完成密码重置。
2. token的生成和验证逻辑不要修改,否则会导致重置链接失效,Django的default_token_generator已经实现了过期时间等安全逻辑。3. 如果后续需要恢复邮件发送,只需要将视图的表单改回默认的PasswordResetForm即可,不需要修改其他配置。通过以上步骤,我们就可以在不破坏Django密码重置核心逻辑的前提下,完全禁用自动邮件发送机制,适配各种个性化的业务通知需求。