You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义用户模型重置密码后登录失败问题求助

Django自定义用户模型密码重置后登录失败问题

我在Django中开发邮箱密码重置系统,采用以username作为唯一标识的自定义用户模型myUser。目前能正常接收重置邮件,但重置密码后使用新密码登录时,系统提示“Invalid credentials”错误。以下是相关代码:

登录视图代码(views.py)

def ilogin(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(request, username=username, password=password)

        if user is not None:
            login(request, user)
            messages.success(request, f'Welcome {username}!')
            return redirect('index')
        else:
            if myUser.objects.filter(username=username).exists():
                messages.error(request, 'Invalid credentials provided.')
            else:
                print('eeeeeee')
                messages.error(request, f'Account with username "{username}" does not exist. Please create an account.')
            return redirect('login')  # Redirect back to login page
    else:
        return render(request, 'user/login.html')

密码重置确认视图代码

def password_reset_confirm(request, token):
    try:
        reset_token = PasswordResetToken.objects.get(token=token)

        if not reset_token.is_valid:
            messages.error(request, 'This reset link is expired or invalid.')
            return redirect('login')
        
        if request.method == 'POST':
            new_password = request.POST.get('new_password')
            confirm_password = request.POST.get('cofirm_password')

            if new_password == confirm_password:
                user = reset_token.user
                print(user)
                user.set_password(new_password)
                user.save()

                reset_token.is_used = True
                reset_token.save()

                messages.success(request, 'Your password has been reset successfully.')
                return redirect('login')
            else:
                messages.error(request, 'Password do not match')

        return render(request, 'emails/password_reset_confirm.html')    

    except PasswordResetToken.DoesNotExist:
        messages.error(request, 'Invalid password reset link')
        return redirect('login')

PasswordResetToken模型代码

from django.db import models
from django.conf import settings
from django.utils import timezone
from django.contrib.auth import get_user_model
# Create your models here.

User = get_user_model()#created a custom user model to use username as unique identifier
class PasswordResetToken(models.Model):
   user       = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
   token      = models.CharField(max_length=100, unique=True)
   created_at = models.DateTimeField(default = timezone.now)  
   is_used    = models.BooleanField(default=False)
   validity_period = 300 #how long the token is valid(5 mins)

   def __str__(self):
       return f'Password reset token for {self.user.username}'
   
   class Meta:
       verbose_name_plural = 'Password Reset Tokens'

   @property
   def is_valid(self):
       return not self.is_used and (timezone.now() - self.created_at).total_seconds() < self.validity_period

自定义用户模型代码

from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager,PermissionsMixin
# Create your models here.

class myUserManager(BaseUserManager):
     def create_user(self,username,email,password=None, **extra_fields):
          if not username:
               raise ValueError('The username field must be included')
          if not email:
               raise ValueError('The email field must be provided')
          
          username = self.model.normalize_username(username)
          email    = self.normalize_email(email)

          extra_fields.pop('email', None)
          user  = self.model( username = username, email=email, **extra_fields )
          user.set_password(password)
          user.save( using = self._db )
          return user
     
     def create_superuser( self,username,email,password=None, **extra_fields ):
          extra_fields.setdefault( 'is_staff', True )
          extra_fields.setdefault( 'is_superuser',True)

          return self.create_user( username, email, password, **extra_fields )

class myUser(AbstractBaseUser,PermissionsMixin):
    username    = models.CharField( max_length = 255, unique=True ) 
    email       = models.EmailField( unique= True )
    is_staff    = models.BooleanField ( default=False ) 
    is_active   = models.BooleanField(default=True) 
    date_joined = models.DateTimeField(auto_now_add=True)  

    objects = myUserManager()

    USERNAME_FIELD  =  'username'
    REQUIRED_FIELDS =   ['email']

    def __str__(self):
         return self.username
    
    class Meta:
         verbose_name        = 'User'
         verbose_name_plural = 'Users'

问题排查与解决方案

1. 修正密码确认字段拼写错误

密码重置确认视图中,获取确认密码的字段名拼写错误:cofirm_password应为confirm_password。如果前端表单的name属性是正确的confirm_password,会导致获取到None,密码对比逻辑异常。修正代码:

confirm_password = request.POST.get('confirm_password')

2. 确认密码哈希保存正常

user.set_password(new_password)会自动哈希密码,重置后可打印user.password确认是否为哈希值(而非明文)。若为明文,说明set_password未正确调用或被覆盖。

3. 验证认证后端配置

确保settings.py中配置了正确的认证后端,默认后端适配自定义用户模型:

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
]

4. 重新获取用户对象避免缓存问题

重置密码时,可重新从数据库获取用户实例,避免可能的缓存导致的更新失效:

user = myUser.objects.get(pk=reset_token.user.pk)
user.set_password(new_password)
user.save()

5. 检查用户is_active状态

确认用户的is_active字段为True(模型默认值为True),若用户被禁用,authenticate会返回None。

6. 测试基础登录功能

用myUser.objects.create_user()创建测试用户,直接尝试登录,确认基础登录逻辑正常,排除自定义用户模型本身的问题。


内容的提问来源于stack exchange,提问作者Sir Keith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 07:23:12