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

更新用户邮箱后Django authenticate验证失败问题排查

Hey there, let's break down what's going wrong here and fix it step by step!

Core Issues Identified

  1. Default Authentication Doesn't Support Email as a Parameter
    Django's built-in authenticate() function only recognizes username and password by default. Your login view uses authenticate(email=email, password=password) which won't work out of the box—this is why your updated email/password combo fails to match.

  2. Redundant & Risky User Update Logic
    In your profile view, you're manually re-updating the user's email after calling email_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:

  1. Create a backends.py file 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
  1. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:52:37