使用 django.contrib.auth.views.password_change 强制执行密码强度要求

Posted

技术标签:

【中文标题】使用 django.contrib.auth.views.password_change 强制执行密码强度要求【英文标题】:Enforcing password strength requirements with django.contrib.auth.views.password_change 【发布时间】:2011-07-10 17:24:46 【问题描述】:

我们有一个 Django 应用程序,它需要特定级别的密码复杂性。我们目前通过客户端 javascript 强制执行此操作,这很容易被有适当动机的人打败。

我似乎找不到任何有关使用 django contrib 内置视图设置服务器端密码强度验证的具体信息。在我重新发明***之前,有没有合适的方法来处理这个要求?

【问题讨论】:

【参考方案1】:

我还为此使用了自定义表单。在urls.py 中指定您的自定义表单:

(r'^change_password/$', 'django.contrib.auth.views.password_change',
     'password_change_form': ValidatingPasswordChangeForm),

PasswordChangeForm 继承并实现验证:

from django import forms
from django.contrib import auth

class ValidatingPasswordChangeForm(auth.forms.PasswordChangeForm):
    MIN_LENGTH = 8

    def clean_new_password1(self):
        password1 = self.cleaned_data.get('new_password1')

        # At least MIN_LENGTH long
        if len(password1) < self.MIN_LENGTH:
            raise forms.ValidationError("The new password must be at least %d characters long." % self.MIN_LENGTH)

        # At least one letter and one non-letter
        first_isalpha = password1[0].isalpha()
        if all(c.isalpha() == first_isalpha for c in password1):
            raise forms.ValidationError("The new password must contain at least one letter and at least one digit or" \
                                        " punctuation character.")

        # ... any other validation you want ...

        return password1

【讨论】:

别忘了django.contrib.auth.forms.SetPasswordForm 对于那些可能不知道@uszywieloryba 在说什么的人,这是用于密码重置的表格。如果您使用此答案的代码,只需使用class ValidatingPasswordForm(object): 而不是class ValidatingPasswordChangeForm(auth.forms.PasswordChangeForm):。然后定义class ValidatingPasswordChangeForm(ValidatingPasswordForm, auth.forms.PasswordChangeForm):class ValidatingSetPasswordForm(ValidatingPasswordForm, auth.forms.SetPasswordForm):,两者都只包含pass【参考方案2】:

Django 1.9 提供了一个内置的password validation 来帮助防止用户使用弱密码。它是通过修改我们项目中的AUTH_PASSWORD_VALIDATORS 设置来启用的。默认情况下,Django 带有以下验证器:

UserAttributeSimilarityValidator,检查两者之间的相似性 用户的密码和一组属性。 MinimumLengthValidator,它只是检查密码是否 满足最小长度。这个验证器配置了一个自定义 选项:现在要求最小长度为九个字符, 而不是默认的八个。 CommonPasswordValidator,检查 密码是否出现在常用密码列表中。经过 默认情况下,它与包含的 1000 个常用密码列表进行比较。 NumericPasswordValidator,检查密码是否不正确 完全是数字。

此示例启用所有四个包含的验证器:

AUTH_PASSWORD_VALIDATORS = [
    
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    ,
    
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': 
            'min_length': 9,
        
    ,
    
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    ,
    
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    ,
]

【讨论】:

如果我通过 API 使用 User.objects.create_user() 方法创建用户,我如何让它在该方法调用上运行密码验证? @Collin - 您需要自己调用验证方法,它们不会因为您将它们放在设置中而自动运行。查看Integrating Validation 的文档。【参考方案3】:

正如一些自定义验证器所逃避的那样,这是我将采取的方法...

创建一个验证器:

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

def validate_password_strength(value):
    """Validates that a password is as least 7 characters long and has at least
    1 digit and 1 letter.
    """
    min_length = 7

    if len(value) < min_length:
        raise ValidationError(_('Password must be at least 0 characters '
                                'long.').format(min_length))

    # check for digit
    if not any(char.isdigit() for char in value):
        raise ValidationError(_('Password must contain at least 1 digit.'))

    # check for letter
    if not any(char.isalpha() for char in value):
        raise ValidationError(_('Password must contain at least 1 letter.'))

然后将验证器添加到您要验证的表单字段中:

from django.contrib.auth.forms import SetPasswordForm

class MySetPasswordForm(SetPasswordForm):

    def __init__(self, *args, **kwargs):
        super(MySetPasswordForm, self).__init__(*args, **kwargs)
        self.fields['new_password1'].validators.append(validate_password_strength)

【讨论】:

我还需要做什么才能使用它吗?我将此代码添加到我的应用程序的 admin.py 中,但它没有被使用。我不知道如何使用 MySetPasswordForm。 @LarryMartell,它对我有用。您确定您的表单中有一个名为“new_password1”的字段吗?如果您在验证器中设置断点,它会命中该断点吗? @TroyGrosfield 错字:“必须容器”-->“必须包含” 优秀的答案。现在我可以根据自己的需要进行定制。【参考方案4】:

我只需安装 django-passwords 并让它为您处理:https://github.com/dstufft/django-passwords

之后,您可以简单地将注册表单子类化并将该字段替换为 PasswordField。

【讨论】:

【参考方案5】:

如果您使用表单或编写一些其他脚本检查正则表达式,我认为您应该编写自己的验证器(或使用 RegexValidator,请参阅:http://docs.djangoproject.com/en/dev/ref/validators/)。这应该是一个简单的任务。另外我认为没有任何内置机制,只是因为每个人对“强密码”概念的理解略有不同。

【讨论】:

我会研究这个方法。我不熟悉 Django,而且我很着急,所以我最终只是实现了我自己版本的 django.contrib.auth.views.password_change 视图,我只是在允许保存密码之前验证密码。它可能比需要的代码多得多。 我对此进行了更多研究,我认为正确的答案确实涉及验证器,但您仍然需要提供自定义表单才能使用验证器。我很快就会写下我的答案。 @jslatts 你有答案吗?

以上是关于使用 django.contrib.auth.views.password_change 强制执行密码强度要求的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)