使用Django的密码重置功能,告知用户邮箱无效

13
我正在使用内置的Django密码重置功能。文档说明如下:链接 如果提供的电子邮件地址不存在于系统中,则该视图不会发送电子邮件,但用户也不会收到任何错误消息。这可以防止信息泄露给潜在攻击者。如果您要在这种情况下提供错误消息,则可以子类化PasswordResetForm并使用password_reset_form参数。
然而,在我的情况下,当用户尝试使用错误的用户名进行重置时,显示错误消息更加重要。
我知道需要做什么,但不知道在子类化PasswordResetForm时应写入什么内容。
子类化PasswordResetForm应包含什么呢?
谢谢。

只需覆盖用户名字段的清理方法即可。 - Brandon Taylor
3个回答

23

所以我最终自己想出了解决方案。这是我的实现:

class EmailValidationOnForgotPassword(PasswordResetForm):
    def clean_email(self):
        email = self.cleaned_data['email']
        if not User.objects.filter(email__iexact=email, is_active=True).exists():
            raise ValidationError("There is no user registered with the specified email address!")

        return email

你还需要在urls.py中添加{'password_reset_form': EmailValidationOnForgotPassword}。这是一个示例:

url(r'^user/password/reset/$',
    'django.contrib.auth.views.password_reset',
    {'post_reset_redirect': '/user/password/reset/done/',
     'html_email_template_name': 'registration/password_reset_email.html',
     'password_reset_form': EmailValidationOnForgotPassword},
    name="password_reset"),

3
您可能需要一个不区分大小写的匹配,并且仅包括活跃用户:这意味着表单不会发送电子邮件。此外,exists()get() 稍微快一些,所以代码应该是 if not User.objects.filter(email__iexact=email, is_active=True).exists(): raise ValidationError - knbk
1
非常好的观察,谢谢!我已经更新了答案。 - Vlad Schnakovszki
我在代码中引发了ValidationError消息,但它不会显示在我的屏幕上:( 请帮帮我。我从'from django.core.exceptions import ValidationError'导入了ValidationError。 - MK Patel

5

对于Django的较新版本,例如Django 2.1,存在一个类似的问题,其中包含稍微修改过的代码。

#forms.py
from django.contrib.auth.forms import PasswordResetForm

class EmailValidationOnForgotPassword(PasswordResetForm):

    def clean_email(self):
        email = self.cleaned_data['email']
        if not User.objects.filter(email__iexact=email, is_active=True).exists():
            msg = _("There is no user registered with the specified E-Mail address.")
            self.add_error('email', msg)
        return email

并且

#urls.py
from accounts.forms import EmailValidationOnForgotPassword

path('accounts/password_reset/', auth_views.PasswordResetView.as_view(form_class=EmailValidationOnForgotPassword), name='password_reset'),

请注意,这可以用于获取用户名/电子邮件。 减少此问题的一种方法是在用户尝试3个不同的电子邮件时立即响应429 Too Many Requests。 例如,可以使用django-ratelimit来实现此目的。

1

forms.py

from django.contrib.auth.forms import PasswordResetForm

class EmailValidationOnForgotPassword(PasswordResetForm):
    def clean_email(self):
        email = self.cleaned_data['email']
        if not NewUser.objects.filter(email__iexact=email, is_active=True).exists():
            raise forms.ValidationError("There is no user registered with the specified email address!")
        return email

urls.py

from users.forms import EmailValidationOnForgotPassword
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('users.urls',namespace='users')),
 
    path('reset_password', auth_views.PasswordResetView.as_view(form_class=EmailValidationOnForgotPassword), name='reset_password'),
    path('reset_password_sent',auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset_password_complete/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

password_reset_form.html

 <form method="post">{% csrf_token %}

   {% if form.errors %}
   {% for field in form %}
   {% for error in field.errors %} 
   <div class="alert alert-danger">
      <strong>{{ error|escape }}</strong>
   </div>
   {% endfor %}
   {% endfor %}
   {% endif %} 

   <div class="form-group">
      <label><strong>Email</strong></label>
      {{ form.email|attr:"type:email"|attr:"class:form-control"|attr:"placeholder:Email" }}
   </div>
   <div class="text-center">
      <button type="submit" class="btn btn-primary btn-block">SUBMIT</button>
   </div>
</form>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接