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

Django REST Framework结合MongoDB时无法用正确账号密码登录

Django + MongoDB 登录失败排查与解决

问题场景

我是Django新手,用MongoDB作为数据库搭建登录/注册功能,用户能成功注册,但输入正确的邮箱和密码登录时,始终返回Invalid email or password。相关代码如下:

serializers.py

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'email', 'first_name', 'last_name', 'password')

models.py

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('The Email field must be set')
        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_doctor', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)


class User(AbstractBaseUser):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    is_active = models.BooleanField(default=True)
    is_doctor = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name']

    objects = UserManager()

    def __str__(self):
        return self.email

views.py(登录逻辑)

@api_view(['POST'])
@csrf_exempt
def login_view(request):
    email = request.data.get('email')
    password = request.data.get('password')

    user = authenticate(request, email=email, password=password)

    if user is not None:
        login(request, user)
        serializer = UserSerializer(user)
        return Response(serializer.data)
    else:
        return Response({'error': 'Invalid email or password'}, status=status.HTTP_401_UNAUTHORIZED)

排查与解决步骤

1. 手动验证密码匹配情况

先绕过authenticate函数,直接查询用户并验证密码,定位问题环节:

@api_view(['POST'])
@csrf_exempt
def login_view(request):
    email = request.data.get('email')
    password = request.data.get('password')

    try:
        user = User.objects.get(email=email)
        # 打印日志确认用户和密码存储状态
        print(f"找到用户: {user.email}")
        print(f"存储的密码哈希: {user.password}")
        
        if user.check_password(password):
            login(request, user)
            serializer = UserSerializer(user)
            return Response(serializer.data)
        else:
            print("密码不匹配")
            return Response({'error': 'Invalid email or password'}, status=status.HTTP_401_UNAUTHORIZED)
    except User.DoesNotExist:
        print("用户不存在")
        return Response({'error': 'Invalid email or password'}, status=status.HTTP_401_UNAUTHORIZED)

通过日志确认:

  • 是否能正确查询到用户
  • 存储的密码是否为Django标准哈希格式(如pbkdf2_sha256$260000$xxxxxx$xxxxxx)
  • check_password是否返回True

2. 检查注册逻辑的正确性

如果密码是明文存储,check_password必然验证失败。确保注册时使用UserManager的create_user方法(该方法会自动哈希密码),而非直接调用User.objects.create():

# 正确的注册视图示例
@api_view(['POST'])
def register_view(request):
    serializer = UserSerializer(data=request.data)
    if serializer.is_valid():
        user = User.objects.create_user(
            email=serializer.validated_data['email'],
            password=serializer.validated_data['password'],
            first_name=serializer.validated_data['first_name'],
            last_name=serializer.validated_data['last_name']
        )
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

3. 确认MongoDB适配的基类

默认的AbstractBaseUser是为SQL数据库设计的,若使用MongoDB(如通过djongo或django-mongodb-engine),需确保模型基类正确适配MongoDB的存储逻辑,避免密码哈希存储异常。

4. 自定义认证后端(可选)

若默认authenticate函数无法适配MongoDB,可自定义认证后端:
在项目中创建backends.py:

from django.contrib.auth.backends import BaseBackend
from .models import User

class EmailBackend(BaseBackend):
    def authenticate(self, request, email=None, password=None, **kwargs):
        try:
            user = User.objects.get(email=email)
            if user.check_password(password) and user.is_active:
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

然后在settings.py中配置:

AUTHENTICATION_BACKENDS = [
    'your_app.backends.EmailBackend',
]

内容的提问来源于stack exchange,提问作者D Binara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:42:03