可配置的密码验证器启动错误

时间:2017-03-14 23:11:34

标签: django

我正在实现一个自定义密码验证程序,它引用管理员用户可以更改的数据库中的设置。一个简化的例子:

class ConfigurableMinimumLengthValidator(object):

  def get_value(self):
      return MyConfigModel.objects.first().password_minimum_length

  def validate(self, password, user=None):
      min_len = self.get_value()
      if len(password) < min_len:
          raise ValidationError("Password too short, must be > %s long." % min_len)

  def get_help_text(self):
      min_len = self.get_value()
      return "Password must be > %s long." % min_len

Django在初始设置期间调用get_help_text(),这大致相当于在模块导入期间进行数据库调用。这导致了各种鸡和蛋的问题:

  • 如果MyConfigModel表尚不存在,比如在新数据库上,则会引发OperationalError。
  • 如果表存在但password_minimum_length字段不存在,则会引发ProgrammingError。
  • 最后,如果该字段存在但表中没有行,那就是MyConfigModel.DoesNotExist异常。那个是可以管理的。

如果没有从settings.py中取出密码验证器,前两个就无法解决,因为错误发生在./manage.py migrate和其他所有管理命令中。

起初我计划捕获这些异常并返回默认值;它会在实际验证期间再次查询。但是我不确定我是否已经考虑过所有可能的异常,我不想使用一个裸的except子句。

有更清洁的方法吗?一些懒惰的代理字符串对象,直到使用才被评估?还是一种检测Django仍在设置的方法?猴子修补安装程序以不调用get_help_text()直到以后?

1 个答案:

答案 0 :(得分:-1)

您需要向验证器类添加init函数,并将参数作为settings.py中的OPTIONS值传递给此函数。以下示例来自django.contrib.auth.password_validation中MinimumLengthValidator的Django 1.11代码。它将min_length作为参数传递:

<强> settings.py

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 15,
        }
    },
]

<强> password_validation.py

class MinimumLengthValidator(object):
    """
    Validate whether the password is of a minimum length.
    """

    def __init__(self, min_length=8):
        self.min_length = min_length

    def validate(self, password, user=None):
        if len(password) < self.min_length:
            raise ValidationError(
                ungettext(
                    "This password is too short. It must contain at least %(min_length)d character.",
                    "This password is too short. It must contain at least %(min_length)d characters.",
                    self.min_length
                 ),
                code='password_too_short',
                params={'min_length': self.min_length},
            )

    def get_help_text(self):
        return ungettext(
            "Your password must contain at least %(min_length)d character.",
            "Your password must contain at least %(min_length)d characters.",
             self.min_length
        ) % {'min_length': self.min_length}

来自https://github.com/django/django的Django代码 版权所有Django软件基金会和个人贡献者 SPDX-License-Identifier:BSD-3-Clause