更新用户邮箱后Django authenticate验证失败问题排查
Hey there, let's break down what's going wrong here and fix it step by step!
Core Issues Identified
Default Authentication Doesn't Support Email as a Parameter
Django's built-inauthenticate()function only recognizesusernameandpasswordby default. Your login view usesauthenticate(email=email, password=password)which won't work out of the box—this is why your updated email/password combo fails to match.Redundant & Risky User Update Logic
In yourprofileview, you're manually re-updating the user's email after callingemail_form.save()—this is unnecessary (the form already handles updating the user instance) and could introduce inconsistencies.
Fix 1: Fix the Authentication Logic
You have two solid options to make email-based login work:
Option A: Pass Email as Username (Quick Fix)
If your user model uses email as the username field (or your users have matching usernames and emails), modify the login view to pass the email as the username parameter:
def user_login(request): form = LoginForm(request.POST) context = {'form': form} if request.POST.get('user_login'): email = request.POST.get('email') password = request.POST.get('password') # Use email as the username for authentication user = authenticate(username=email, password=password) if user is not None: login(request, user) return redirect('profile') else: messages.error(request, 'Email and Password does not match.') return redirect('login') return render(request, 'users/login.html', context)
Option B: Custom Authentication Backend (More Robust)
Create a custom backend to let Django authenticate users via email directly:
- Create a
backends.pyfile in your app:
from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model User = get_user_model() class EmailBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: # Look up user by email user = User.objects.get(email=kwargs['email']) except User.DoesNotExist: return None # Validate password if user.check_password(password): return user return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
- Add this backend to your
settings.py:
AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', # Keep default backend 'your_app_name.backends.EmailBackend', # Add your custom backend ]
Now your original authenticate(email=email, password=password) call will work as expected.
Fix 2: Clean Up Redundant Profile Update Code
Your profile view has unnecessary steps—simplify it to avoid confusion:
@login_required def profile(request): ... elif request.POST.get('update_email'): # Fetch Customer via the authenticated user (more reliable than email lookup) data = Customer.objects.get(user=request.user) email_form = UpdateEmailForm(request.POST, instance=request.user) if email_form.is_valid(): # Form save already updates the user's email email_form.save() # Update Customer's email with the already-updated user email data.email = request.user.email data.save() messages.success(request, 'Your account has been updated successfully') return redirect('profile') else: return render(request, 'users/profile.html', {'data': data, 'email_form': email_form})
Bonus: Refine the UpdateEmailForm
Make a small improvement to your form for better practice:
from django.contrib.auth import get_user_model from django import forms User = get_user_model() class UpdateEmailForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput()) new_email = forms.EmailField() class Meta: model = User fields = ['new_email', 'password'] def clean(self): cleaned_data = super().clean() # Always call parent clean method first old_password = cleaned_data.get('password') # Use the user instance's built-in check_password method if not self.instance.check_password(old_password): raise forms.ValidationError('Incorrect password. Please try again.') return cleaned_data
These changes should resolve your authentication issue and clean up your update logic. Let me know if you run into any other snags!
内容的提问来源于stack exchange,提问作者juju

