Python Django密码重置:新密码必须不同于用户提交的最后四个密码中的任何一个

Python Django密码重置:新密码必须不同于用户提交的最后四个密码中的任何一个,python,django,security,Python,Django,Security,我是Django新手,请帮助我如何实现密码重置,以便新密码必须不同于用户在Django中提交的最后四个密码中的任何一个: 我正在使用默认的django密码重置: URL.py: django/contrib/auth/views.py: @csrf_protect def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.h

我是Django新手,请帮助我如何实现密码重置,以便新密码必须不同于用户在Django中提交的最后四个密码中的任何一个:

我正在使用默认的django密码重置: URL.py:

django/contrib/auth/views.py:

@csrf_protect
def password_reset(request, is_admin_site=False,
                   template_name='registration/password_reset_form.html',
                   email_template_name='registration/password_reset_email.html',
                   subject_template_name='registration/password_reset_subject.txt',
                   password_reset_form=PasswordResetForm,
                   token_generator=default_token_generator,
                   post_reset_redirect=None,
                   from_email=None,
                   current_app=None,
                   extra_context=None):
    if post_reset_redirect is None:
        post_reset_redirect = reverse('django.contrib.auth.views.password_reset_done')
    if request.method == "POST":
        form = password_reset_form(request.POST)
        if form.is_valid():
            opts = {
                'use_https': request.is_secure(),
                'token_generator': token_generator,
                'from_email': from_email,
                'email_template_name': email_template_name,
                'subject_template_name': subject_template_name,
                'request': request,
            }
            if is_admin_site:
                opts = dict(opts, domain_override=request.get_host())
            form.save(**opts)
            return HttpResponseRedirect(post_reset_redirect)
    else:
        form = password_reset_form()
    context = {
        'form': form,
    }
    if extra_context is not None:
        context.update(extra_context)
    return TemplateResponse(request, template_name, context,
                            current_app=current_app)

我是否应该创建数据库表来存储用户以前的所有密码,或者是否有任何django库可以为我提供此功能。

是的,您可以创建一个模型,并在密码重置/更改时存储用户的所有密码

from django.contrib.auth.models import User
import json

class OldPasswords(models.Model):
    user = model.ForeignKey(User)
    pwd = models.CharField(max_length=200)

    def setPasswords(self, pwd):
        self.pwd = json.dumps(pwd)

    def getPasswords(self):
        return json.loads(self.pwd)
在密码重置/更改时创建一个信号并保存当前密码

例如:

from allauth.account.signals import password_changed, password_reset
def send_password_changed_email(sender, **kwargs):
    user = kwargs.get('user')
    if user:
       pwds = OldPasswords.objects.get_or_create(user=user)
       pwds.setPasswords(pwd)
保存到模型后,您需要实现自定义验证器,以便在用户在重置时尝试旧密码时显示验证消息:

  • 验证(self,password,user=None):验证密码。如果密码有效,则返回None,或者使用 如果密码无效,则显示错误消息。你必须能够 处理用户为无-如果这意味着您的验证器无法运行, 只需返回None,就不会有错误

  • get_help_text():提供帮助文本向用户解释需求

验证程序的AUTH_PASSWORD_验证程序中的选项中的任何项都将传递给构造函数。所有构造函数参数都应具有默认值

下面是验证器的基本示例,具有一个可选设置:

from django.core.exceptions import ValidationError
from yourapp.model import OldPasswords 
from django.utils.translation import ugettext as _

class PasswordValidator(object):
    def __init__(self, password):
        self.password = password

    def validate(self, password, user=None):
        pwd_list = OldPasswords.objects.get(user=user).getPasswords() 
        if password in pwd_list:
            raise ValidationError(
                _("You used this password recently. Please choose a different one."),
                code='password_recently_used',
                params={'min_length': self.min_length},
            )

    def get_help_text(self):
        return _(
            "You used this password recently. Please choose a different one."
        )

但是,如果您决定存储用户以前的密码,则不应以明文形式存储。

谢谢您提供的详细答案。请帮助我如何在我的pass_reset视图或模板中使用PasswordValidator。密码验证是在AUTH_Password_VALIDATORS设置中配置的:
AUTH_Password_VALIDATORS=[{'NAME':'django.contrib.AUTH.Password_validation.UserAttributesMilarityValidator',},]
from django.core.exceptions import ValidationError
from yourapp.model import OldPasswords 
from django.utils.translation import ugettext as _

class PasswordValidator(object):
    def __init__(self, password):
        self.password = password

    def validate(self, password, user=None):
        pwd_list = OldPasswords.objects.get(user=user).getPasswords() 
        if password in pwd_list:
            raise ValidationError(
                _("You used this password recently. Please choose a different one."),
                code='password_recently_used',
                params={'min_length': self.min_length},
            )

    def get_help_text(self):
        return _(
            "You used this password recently. Please choose a different one."
        )