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)
问题原因分析
- 密码被重复哈希:注册时,
register视图里用make_password哈希了一次密码,同时RegistrationForm的save方法又再次调用make_password哈希密码,导致数据库里存的是哈希两次的结果,登录时用原密码验证肯定不匹配。 - 自定义模型不兼容Django认证系统:
Customer模型没有继承Django的用户基类,authenticate函数无法识别用email作为登录凭证,所以即使密码验证通过,authenticated_user也会是None,进而触发错误提示。 - 冗余的空格处理:对存储的哈希密码调用
.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函数,需要修改模型继承关系:
- 更新
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})"
- 在
settings.py中配置:
AUTH_USER_MODEL = '你的应用名.Customer' # 替换成实际应用名称 AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ]
- 执行数据库迁移:
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
相关产品推荐
相关产品推荐

