You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让Django为无可用密码的社交登录用户发送重置密码邮件?

解决Django无密码用户无法触发重置密码邮件的问题

我之前也碰到过一模一样的场景——社交登录创建的用户根本没设置过密码,想切换成邮箱密码登录时,发密码重置邮件居然没反应!查了才知道Django默认会跳过那些没有可用密码的用户,默认认为这类用户应该用LDAP之类的认证方式,但咱们的需求就是要让这些用户通过重置邮件来设置密码,总不能注册时给个随机密码,用户根本搞不清状况对吧?

别急,咱们只需要两步就能搞定:

1. 自定义密码重置表单,跳过可用密码检查

Django自带的PasswordResetForm里,get_users方法会过滤掉has_usable_password()返回False的用户。咱们要做的就是重写这个方法,把这个过滤条件去掉。

在你的app里新建(或修改)forms.py,加入以下代码:

from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth import get_user_model

UserModel = get_user_model()

class CustomPasswordResetForm(PasswordResetForm):
    def get_users(self, email):
        """重写方法,包含无可用密码的活跃用户"""
        email_field_name = UserModel.get_email_field_name()
        # 只筛选活跃且邮箱匹配的用户,去掉密码可用性检查
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % email_field_name: email,
            'is_active': True,
        })
        return (u for u in active_users)

2. 在URL配置中替换默认的重置视图

接下来,咱们要告诉Django使用咱们自定义的表单来处理密码重置请求。修改项目的urls.py

from django.contrib.auth import views as auth_views
from .forms import CustomPasswordResetForm  # 注意替换成你的forms实际路径

urlpatterns = [
    # 替换默认的密码重置视图,指定用自定义表单
    path('password-reset/', auth_views.PasswordResetView.as_view(
        form_class=CustomPasswordResetForm
    ), name='password_reset'),
    
    # 下面这些默认视图不用改,直接保留就行
    path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

为什么这样可行?

修改后,不管用户有没有设置过密码,只要是活跃用户且邮箱匹配,就能收到重置邮件。而当用户点击邮件里的链接后,Django自带的PasswordResetConfirmView会用SetPasswordForm让用户设置新密码——这个表单本来就不需要旧密码,刚好适配无密码用户的场景,设置完成后用户的密码就会被正常哈希存储,之后就能用邮箱密码登录啦。

这样就完美避开了注册时设置随机密码的尴尬,流程对用户来说也更直观~

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

火山引擎 最新活动