Django REST Framework登录接口认证失败问题求助
Django REST Framework 登录认证失败问题排查与修复
核心问题分析
你的登录接口认证失败主要由以下3个问题导致:
1. 错误从serializer.data获取密码
serializer.data是序列化后的输出数据,如果密码字段设置为write_only=True,该字段不会出现在data中。登录时应该从serializer.validated_data(验证通过的输入数据)中提取邮箱和密码。
2. 登录序列化器未正确配置密码字段
UserLoginSerializer继承自ModelSerializer,但未显式将password设为write_only=True,且没有覆盖为明文输入的CharField(模型中password是哈希存储,登录需要接收明文密码)。
3. 用户模型可能未配置邮箱作为登录凭证
如果自定义User模型未设置USERNAME_FIELD = 'email',authenticate(email=xxx, password=xxx)会失效——Django默认使用username字段做认证匹配。
修复代码
1. 修复serializers.py中的UserLoginSerializer
推荐改用Serializer而非ModelSerializer(登录不需要序列化用户模型返回),并添加基础验证逻辑:
from rest_framework import serializers from authentication.models import User class UserRegistrationSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) class Meta: model = User fields = ["email", "username", "password", "password2"] extra_kwargs = {"password": {"write_only": True}} def validate(self, attrs): password = attrs.get("password") password2 = attrs.get("password2") if password != password2: raise serializers.ValidationError( "密码与确认密码不匹配" ) return attrs def create(self, validated_data): # 移除多余的password2字段再创建用户 validated_data.pop('password2') return User.objects.create_user(**validated_data) # 修复后的登录序列化器 class UserLoginSerializer(serializers.Serializer): email = serializers.EmailField(max_length=100) password = serializers.CharField(style={"input_type": "password"}, write_only=True) def validate(self, attrs): email = attrs.get('email') # 提前验证邮箱是否已注册 if not User.objects.filter(email=email).exists(): raise serializers.ValidationError("该邮箱未注册") return attrs
2. 修复views.py中的UserLoginView
改用validated_data获取参数,并修正认证逻辑和状态码(401表示未授权,比404更符合语义):
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from django.contrib.auth import authenticate from authentication.serializers import UserLoginSerializer, UserRegistrationSerializer class UserRegistrationView(APIView): def post(self, request, format=None): serializer = UserRegistrationSerializer(data=request.data) if serializer.is_valid(raise_exception=True): user = serializer.save() return Response( {"msg": "注册成功"}, status=status.HTTP_201_CREATED ) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class UserLoginView(APIView): def post(self, request, format=None): serializer = UserLoginSerializer(data=request.data) if serializer.is_valid(raise_exception=True): # 从validated_data获取验证后的输入值 email = serializer.validated_data.get('email') password = serializer.validated_data.get('password') # 若User模型设置了USERNAME_FIELD = 'email',直接用email参数;否则改用username=email user = authenticate(request=request, email=email, password=password) if user is not None: return Response({"msg": "登录成功"}, status=status.HTTP_200_OK) else: return Response( { "errors": { "non_field_errors": ["邮箱或密码不正确"] } }, status=status.HTTP_401_UNAUTHORIZED ) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3. 确认自定义User模型配置(关键)
确保models.py中的User模型设置了邮箱作为登录凭证,并在settings.py中指定自定义用户模型:
# authentication/models.py from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models class UserManager(BaseUserManager): def create_user(self, email, username, password=None, **extra_fields): if not email: raise ValueError('用户必须提供邮箱') email = self.normalize_email(email) user = self.model(email=email, username=username, **extra_fields) user.set_password(password) user.save(using=self._db) return user class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) username = models.CharField(max_length=100) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) USERNAME_FIELD = 'email' # 核心:设置邮箱为登录验证字段 REQUIRED_FIELDS = ['username'] objects = UserManager()
在项目根目录的settings.py中添加:
AUTH_USER_MODEL = 'authentication.User'
内容的提问来源于stack exchange,提问作者muyiwa. py
相关产品推荐
相关产品推荐

