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

Django登录密码验证失败求助:输入正确却提示错误

Django登录密码验证失败问题

问题描述

注册时确认密码输入正确,但登录系统始终提示密码错误,无法正常登录,找不到问题原因。

相关代码

views.py

from django.contrib.auth.hashers import make_password, check_password
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth import authenticate, login
from .forms import RegistrationForm, LoginForm
from django.shortcuts import render, redirect
from django.contrib import messages
from django.shortcuts import HttpResponse
from .models import *

# Create your views here.
def home(request):
    return render (request,"home.html")

def register(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data.get('email').strip()  # Trim leading and trailing whitespace
            password = form.cleaned_data.get('password1').strip()  # Trim leading and trailing whitespace
            if Customer.objects.filter(email=email).exists():
                messages.error(request, "A customer with this email already exists.")
                return redirect('user_register')
            # Hash the password using make_password
            encrypted_password = make_password(password)
            customer = Customer.objects.create(
                username=form.cleaned_data['username'],
                firstname=form.cleaned_data['firstname'],
                lastname=form.cleaned_data['lastname'],
                email=email,
                address=form.cleaned_data['address'],
                phone=form.cleaned_data['phone'],
                birthdate=form.cleaned_data['birthdate'],
                password1=encrypted_password
            )
            messages.success(request, "You registered successfully!")
            return redirect('login')
    else:
        form = RegistrationForm()
    return render(request, "register.html", {'form': form})

def user_login(request):
    if request.method == 'POST':
        email = request.POST.get('email').strip()  # Trim leading and trailing whitespace
        password = request.POST.get('password').strip()  # Trim leading and trailing whitespace
        try:
            user = Customer.objects.get(email=email)
            stored_password = user.password1.strip()  # Trim leading and trailing whitespace from stored password

            # Debugging: Print or log variable values
            print("Email:", email)
            print("Password:", password)
            print("Stored Password:", stored_password)

            # Check if the provided password matches the stored hashed password
            if check_password(password, stored_password):
                # Authenticate the user
                authenticated_user = authenticate(request, email=email, password=password)
                if authenticated_user is not None:
                    # Log in the authenticated user
                    login(request, authenticated_user)
                    messages.success(request, "Login successfully!")
                    return redirect('home')
                else:
                    # Incorrect password
                    messages.error(request, "Incorrect password. Please try again. #1")
                    return redirect('login')
            else:
                # Incorrect password
                messages.error(request, "Incorrect password. Please try again. #2")
                return redirect('login')
        except Customer.DoesNotExist:
            # Incorrect email
            messages.error(request, "Incorrect email. Please try again.")
            return redirect('login')
    else:
        form = LoginForm()
        return render(request, "login.html", {'form': form})

models.py

from django.db import models
from django.core.validators import MinValueValidator
    
class Customer(models.Model):
    username = models.CharField(max_length=200, null=True)
    firstname = models.CharField(max_length=200, null=True)
    lastname = models.CharField(max_length=200, null=True)
    email = models.EmailField(max_length=200, null=True)
    address = models.CharField(max_length=200, null=True)
    phone = models.CharField(max_length=11, null=True)
    birthdate = models.DateField(null=True)
    password1 = models.CharField(max_length=256, null=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)
        
    def __str__(self):
        return  f"({self.firstname} {self.lastname} {self.email})"
    
class Menu(models.Model):
    name = models.CharField(max_length=200, null=True)
    price = models.DecimalField(max_digits=10, decimal_places=2,null=True)    
    
    def __str__(self):
        return self.name

forms.py

from django import forms
from .models import Customer
from django.contrib.auth.hashers import make_password

class RegistrationForm(forms.ModelForm):
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput)

    class Meta:
        model = Customer
        fields = ['username', 'firstname', 'lastname', 'email', 'address', 'phone', 'birthdate', 'password1', 'password2']
                
    def clean_email(self):
        email = self.cleaned_data['email']
        if Customer.objects.filter(email=email).exists():
            raise forms.ValidationError("This email address is already in use.")
        return email
    
    def clean(self):
        cleaned_data = super().clean()
        password1 = cleaned_data.get("password1")
        password2 = cleaned_data.get("password2")
        if password1 != password2:
            raise forms.ValidationError("Passwords do not match.")
        return cleaned_data
    
    def save(self, commit=True):
        user = super().save(commit=False)
        user.password1 = make_password(self.cleaned_data['password1'])
        if commit:
            user.save()
        return user
    
class LoginForm(forms.Form):
    email = forms.EmailField(max_length=200)
    password1 = forms.CharField(label='Password1', widget=forms.PasswordInput)

问题原因分析

  1. 密码被重复哈希:注册时,register视图里用make_password哈希了一次密码,同时RegistrationForm的save方法又再次调用make_password哈希密码,导致数据库里存的是哈希两次的结果,登录时用原密码验证肯定不匹配。
  2. 自定义模型不兼容Django认证系统:Customer模型没有继承Django的用户基类,authenticate函数无法识别用email作为登录凭证,所以即使密码验证通过,authenticated_user也会是None,进而触发错误提示。
  3. 冗余的空格处理:对存储的哈希密码调用.strip()完全没必要,哈希字符串本身不会包含空格,属于无效操作。

解决方案

方案1:修复注册逻辑,避免重复哈希

直接使用表单的save方法创建用户,因为表单已经处理了密码哈希,不需要手动再处理:

def register(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            # 表单的save方法已完成密码哈希和用户创建
            form.save()
            messages.success(request, "注册成功!")
            return redirect('login')
    else:
        form = RegistrationForm()
    return render(request, "register.html", {'form': form})

方案2:让Customer模型兼容Django认证系统

如果要继续使用Django的authenticate和login函数,需要修改模型继承关系:

  1. 更新models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

class CustomerManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('用户必须提供邮箱')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)

class Customer(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=200, null=True)
    firstname = models.CharField(max_length=200, null=True)
    lastname = models.CharField(max_length=200, null=True)
    email = models.EmailField(max_length=200, unique=True)
    address = models.CharField(max_length=200, null=True)
    phone = models.CharField(max_length=11, null=True)
    birthdate = models.DateField(null=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = CustomerManager()

    USERNAME_FIELD = 'email'  # 设置邮箱为登录字段
    REQUIRED_FIELDS = []

    def __str__(self):
        return f"({self.firstname} {self.lastname} {self.email})"
  1. 在settings.py中配置:
AUTH_USER_MODEL = '你的应用名.Customer'  # 替换成实际应用名称
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
]
  1. 执行数据库迁移:
python manage.py makemigrations
python manage.py migrate

方案3:简化登录逻辑(不依赖Django认证)

如果不想修改用户模型,可以跳过authenticate步骤,手动处理登录会话:

def user_login(request):
    if request.method == 'POST':
        email = request.POST.get('email').strip()
        password = request.POST.get('password').strip()
        try:
            user = Customer.objects.get(email=email)
            # 去掉不必要的strip()
            if check_password(password, user.password1):
                # 手动设置会话标记用户已登录
                request.session['user_id'] = user.id
                messages.success(request, "登录成功!")
                return redirect('home')
            else:
                messages.error(request, "密码错误,请重试。")
                return redirect('login')
        except Customer.DoesNotExist:
            messages.error(request, "邮箱不存在,请重试。")
            return redirect('login')
    else:
        form = LoginForm()
        return render(request, "login.html", {'form': form})

注意:这种方式需要在其他视图中自行验证用户会话,比如检查request.session.get('user_id')是否存在。

内容的提问来源于stack exchange,提问作者Sam Altoveros

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:07:03