[Django]-Django Password reset: new password must be different from any of the last four passwords user has submitted

3👍

Yes, you can create a model and store all the passwords of a user whenever password reset/changed.

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)

create a signal while password reset/changed and save current password.

for example:

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)

After saving to the model, you need to implement custom validator to show validation message when user try the old password while reset:

  • validate(self, password, user=None): validate a password. Return None if the password is valid, or raise a ValidationError with an
    error message if the password is not valid. You must be able to
    deal with user being None – if that means your validator can’t run,
    simply return None for no error.

  • get_help_text(): provide a help text to explain the requirements to the user.

Any items in the OPTIONS in AUTH_PASSWORD_VALIDATORS for your validator will be passed to the constructor. All constructor arguments should have a default value.

Here’s a basic example of a validator, with one optional setting:

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."
        )

However, if you decide to store a user’s previous passwords, you should never do so in clear text.

👤Vijay

Leave a comment