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

Django REST Framework自定义用户模型的邮箱登录验证失败问题

Django REST Framework自定义用户模型的邮箱登录验证失败问题

嘿,我看你已经卡了48小时了,先别着急,咱们一点点排查问题。你的核心需求是用邮箱+密码登录获取Token,但现在一直返回401,咱们先从代码里的几个关键问题入手:

一、自定义认证后端(EmailBackend)里的明显错误

你看这段代码:

except UserModel.DoesNotExist:
    UserModel().set_password(password)

这行代码完全是无效的——当用户不存在时,你创建了一个临时的User实例并设置了密码,但既没保存也没返回任何值,直接跳过了后续逻辑,这会导致authenticate最终返回None,触发“Invalid Email or Password”。

修复方法:当用户不存在时直接返回None,因为不存在的用户肯定无法通过验证:

except UserModel.DoesNotExist:
    return None  # 用户不存在,直接返回None

另外,还有个小细节:你的UserModel最好用Django提供的get_user_model()来获取当前配置的用户模型,避免硬编码。修改你的EmailBackend开头:

from django.contrib.auth import get_user_model
UserModel = get_user_model()

二、检查Settings.py里的关键配置

这两步必须配置,否则Django还是会用默认的用户模型和认证后端:

  1. 告诉Django使用你的自定义用户模型:
AUTH_USER_MODEL = "你的应用名.CustomUser"  # 比如"accounts.CustomUser"
  1. 指定使用你的自定义认证后端:
AUTHENTICATION_BACKENDS = [
    "你的应用名.backends.EmailBackend",  # 比如"accounts.backends.EmailBackend"
    # 如果需要保留默认的用户名登录,可以加上下面这行,否则只留上面一行即可
    "django.contrib.auth.backends.ModelBackend",
]

三、登录序列化器(LoginSerializer)的小优化

你的LoginSerializer用了ModelSerializer,但password字段默认不是write_only的,虽然不影响输入,但为了规范和避免后续问题,最好显式设置:

class LoginSerializer(serializers.ModelSerializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)  # 显式设为只写

    class Meta:
        model = CustomUser
        fields = ['email','password']

四、确认用户创建时密码是否正确哈希

如果你的CustomUserManager没有正确实现create_user方法,创建用户时密码会是明文存储,导致check_password验证失败。检查你的CustomUserManager:

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("The Email must be set")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)  # 这一步必须有,用来哈希密码
        user.save()
        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)

如果你的Manager里没有set_password这一步,赶紧加上,然后重新创建测试用户(之前创建的用户密码是明文,需要重新创建)。

五、最后检查LoginAPIView里的逻辑

你的LoginAPIView逻辑基本没问题,但可以加个小调试:在authenticate之后打印一下user的值,看看是None还是有值,帮助定位问题:

user = authenticate(request, username=email, password=password)
print("Authenticated user:", user)  # 调试用,生产环境去掉

按照上面的步骤逐一排查修改,应该就能解决你的登录问题了!

备注:内容来源于stack exchange,提问作者lem thee stallion

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 12:54:36