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
相关产品推荐
相关产品推荐

