
本文详解如何在 django rest framework 项目中高效实现“忘记密码”和“修改密码”等基础认证相关 api,涵盖官方设计哲学、推荐第三方方案及手写轻量级实现的最佳实践。
本文详解如何在 django rest framework 项目中高效实现“忘记密码”和“修改密码”等基础认证相关 api,涵盖官方设计哲学、推荐第三方方案及手写轻量级实现的最佳实践。
Django REST Framework(DRF)本身专注于提供灵活、可扩展的 API 构建能力,而非预置业务逻辑密集型的认证流程。因此,像「用户密码重置(Forgot Password)」和「登录态下密码修改(Change Password)」这类功能——尽管常见——并未被 DRF 或 Django 内置为开箱即用的 API 视图。其根本原因在于:这些流程高度依赖具体业务规则(如邮箱验证时效、密码强度策略、是否强制旧密码校验、是否需短信二次确认等),DRF 选择保持中立,仅提供底层组件(如 TokenAuthentication、PasswordResetForm、SetPasswordForm),由开发者按需组合。
✅ 推荐方案一:使用成熟第三方包(快速上线)
最主流的选择是 dj-rest-auth(原 django-rest-auth),它专为 DRF 设计,无缝集成 Django 的认证系统,并已内置以下标准端点:
| 端点 | 方法 | 功能 |
|---|---|---|
| /api/auth/password/reset/ | POST | 提交邮箱触发重置邮件(含 token 链接) |
| /api/auth/password/reset/confirm/ | POST | 提交新密码 + uidb64 + token 完成重置 |
| /api/auth/password/change/ | POST | 登录用户修改密码(需传入旧密码) |
安装与配置示例:
pip install dj-rest-auth django-allauth
settings.py 中添加:
INSTALLED_APPS += [
'django.contrib.sites',
'allauth',
'allauth.account',
'dj_rest_auth',
'dj_rest_auth.registration',
]
SITE_ID = 1
REST_AUTH = {
'USE_JWT': True,
'JWT_AUTH_COOKIE': 'my-app-auth',
}urls.py:
from django.urls import path, include
urlpatterns = [
path('api/auth/', include('dj_rest_auth.urls')),
path('api/auth/registration/', include('dj_rest_auth.registration.urls')),
]⚠️ 注意事项:
- dj-rest-auth 依赖 django-allauth 处理邮件模板与 token 生成逻辑,务必配置 EMAIL_BACKEND 并测试 SMTP;
- 重置链接中的 uidb64 和 token 由 Django 的 default_token_generator 生成,有效期默认为 3 天(可通过 PASSWORD_RESET_TIMEOUT 调整);
- 若需自定义邮件内容,覆盖 registration/password_reset_email.html 模板即可。
✅ 推荐方案二:手写精简版(完全可控)
若项目要求极简、无额外依赖,或需深度定制(如对接企业微信通知、审计日志),可基于 DRF 原生类快速构建:
# serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model, password_validation
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
User = get_user_model()
class PasswordResetSerializer(serializers.Serializer):
email = serializers.EmailField()
def validate_email(self, value):
if not User.objects.filter(email__iexact=value).exists():
raise serializers.ValidationError("用户不存在。")
return value
def save(self):
request = self.context.get('request')
form = PasswordResetForm(data={'email': self.validated_data['email']})
if form.is_valid():
form.save(
request=request,
use_https=request.is_secure(),
email_template_name='registration/password_reset_email.txt',
)
return {}
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
class PasswordResetView(APIView):
permission_classes = []
serializer_class = PasswordResetSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"detail": "密码重置邮件已发送。"})? 总结:
DRF 不提供“开箱即用”的密码管理 API,并非功能缺失,而是遵循“显式优于隐式”与“解耦业务逻辑”的工程原则。对于 MVP 项目,优先选用 dj-rest-auth;对于高合规、强定制场景,则建议封装清晰的序列化器 + 视图 + 测试用例,既保障安全性(如速率限制、token 一次性校验),又保留长期可维护性。无论哪种路径,都应确保所有密码操作走 HTTPS、敏感字段不返回明文、错误提示避免泄露用户存在性信息(如统一提示“如账户存在,邮件已发送”)。










