Home > Net >  Django PasswordResetView does not work for inactive users
Django PasswordResetView does not work for inactive users

Time:11-14

I have a simple django app where users can create and login to their accounts.

When a user is registering for a new account, the user object is created and saved in the database with the is_active flag set to false. Once the user clicks the confirmation email, the user object has its is_active flag set to true.

I have built out a password reset flow using Django's views: PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView, and PasswordResetCompleteView.

Everything works as expected unless I am trying to reset the password for an account which has not yet been activated (is_active == False), in which case, the reset password email is never sent to the user.

The edge case I am considering here is for a user who created an account, and never clicked the registration link which expires after 72 hours, and thus have a user account which exists but is not active. Then the user wants to get a new registration link, and to do so I require a user to enter their username and password (so that no malicious actors can spam a random users email inbox with new registration link emails). If the user has since forgotten their password, they are bricked and cannot activate their account, nor can they refresh their password.

How can I send a password reset link to accounts which are not active?

CodePudding user response:

have you tried to use django-allauth?

I think it solves this. Django AllAuth - How to manually send a reset-password email?

CodePudding user response:

I was able to solve this by creating my own child of Django's PasswordResetForm and overriding the get_users method which checks if a user is_active.

class ResetPasswordForm(PasswordResetForm):
    
    # Override the get_users method and delete the requirement that a user is_active
    # This is to account for the edge case where a user registered an account
    # but never accepted the registration email, then they also forget their
    # password, we need to be able to send a password reset link for a non active
    # user.
    def get_users(self, email):
        """Given an email, return matching user(s) who should receive a reset.

        This allows subclasses to more easily customize the default policies
        that prevent inactive users and users with unusable passwords from
        resetting their password.
        """
        email_field_name = UserModel.get_email_field_name()
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % email_field_name: email
        })
        return (
            u for u in active_users
            if u.has_usable_password() and
            _unicode_ci_compare(email, getattr(u, email_field_name))
        )

The is_active requirement was originally introduced to Djangos PasswordResetForm here.

  • Related