【问题标题】:Django Password reset: new password must be different from any of the last four passwords user has submittedDjango密码重置:新密码必须与用户提交的最后四个密码中的任何一个不同
【发布时间】:2015-07-30 16:17:22
【问题描述】:

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

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

url(r'^password/reset/$',auth_views.password_reset,      
          name='auth_password_reset'),

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 库可以为我提供此功能。

【问题讨论】:

    标签: python django security


    【解决方案1】:

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

    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)
    

    保存到模型后,您需要实现自定义验证器,以在用户在重置时尝试旧密码时显示验证消息:

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

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

    验证器的 AUTH_PASSWORD_VALIDATORS 中的 OPTIONS 中的任何项目都将传递给构造函数。所有构造函数参数都应该有一个默认值。

    这是一个验证器的基本示例,带有一个可选设置:

    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.UserAttributeSimilarityValidator', },]
    猜你喜欢
    • 1970-01-01
    • 2020-01-13
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多