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

Django Rest API登录返回401 Unauthorized问题求助

Django Rest API登录401 Unauthorized问题排查修复

核心问题1:自定义User模型错误覆盖password字段

你的CustomUser模型自己定义了password = models.CharField(max_length = 25,default = "no password"),这会覆盖AbstractUser自带的密码字段(AbstractUser的password是经过哈希处理的),导致注册时密码被明文存储,而authenticate方法需要验证哈希后的密码,因此永远验证失败。

修复:
删除自定义的password字段,AbstractUser已包含该字段,无需重复定义:

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(default="no email", unique=True)
    first_name = models.CharField(max_length=25, default='No name')
    last_name = models.CharField(max_length=25, default='No surname')
    
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
    
    def getDetails(self):
        return {
            'email': self.email,
            'first_name': self.first_name,
            'last_name': self.last_name
        }

核心问题2:UserSerializer未处理密码哈希

默认的ModelSerializer.save()不会对密码进行哈希处理,即使去掉自定义password字段,注册时密码仍会明文存入数据库,导致authenticate验证失败。

修复:
在UserSerializer中重写create方法,用set_password()对密码进行哈希:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomUser
        fields = ['id','email','password','first_name','last_name']
        extra_kwargs = {'password': {'write_only': True}}
    
    def create(self, validated_data):
        password = validated_data.pop('password')
        user = super().create(validated_data)
        user.set_password(password)
        user.save()
        return user

问题3:user_login视图的冗余与参数问题

视图里的user = None; if not user:是冗余代码,且authenticate参数需要匹配Django的验证逻辑:

@api_view(['POST'])
def user_login(request):
    if request.method == 'POST':
        email = request.data.get('email')
        password = request.data.get('password')
        # 用username参数匹配USERNAME_FIELD对应的email字段
        user = authenticate(request=request, username=email, password=password)
        
        if user:
            token, _ = Token.objects.get_or_create(user=user)
            return Response({**user.getDetails(), 'token': token.key}, status=status.HTTP_200_OK)
        return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)

问题4:类视图UserLoginAPIView的多处错误

这个视图存在多个语法与逻辑错误,修复后如下(假设使用simplejwt生成Token):

from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.permissions import AllowAny

# 先定义LoginSerializer用于验证登录凭证
class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)
    
    def validate(self, attrs):
        email = attrs.get('email')
        password = attrs.get('password')
        
        user = authenticate(request=self.context.get('request'), username=email, password=password)
        
        if not user:
            raise serializers.ValidationError('Invalid credentials')
        
        attrs['user'] = user
        return attrs

class UserLoginAPIView(generics.GenericAPIView):
    permission_classes = [AllowAny]
    serializer_class = LoginSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        
        token = RefreshToken.for_user(user)
        data = {
            **user.getDetails(),
            "token": {"refresh": str(token), "access": str(token.access_token)}
        }
        return Response(data, status=status.HTTP_200_OK)

额外检查项

  • 确保settings.py中配置了正确的用户模型:AUTH_USER_MODEL = '你的应用名.CustomUser'
  • 修改模型后执行数据库迁移:python manage.py makemigrations && python manage.py migrate
  • 注册新用户后,在Admin面板确认密码字段是哈希值(而非明文)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:07:47