401 неавторизованный вход в Django Rest API

У меня проблемы с конечной точкой API для входа в систему; она работала в последний раз, когда я проверял, а теперь после нескольких часов работы вслепую она больше не работает, и я не знаю, что я сделал. :)

Регистрация работает без проблем, пользователь также создается в базе данных и виден в панели администратора. Для входа в систему те же учетные данные не работают. Я привел код ниже:

views.py

#register new users
@api_view(['POST'])
def register_user(request):
    if request.method == 'POST':
        serializer = UserSerializer(data= request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data,status=status.HTTP_201_CREATED)
        return Response(serializer.data,status=status.HTTP_400_BAD_REQUEST)

#userlogin with authentication tokens
@api_view(['POST'])
def user_login(request):
    if request.method == 'POST':
        email = request.data.get('email')
        password = request.data.get('password')
        user = None
        if not user:
            user = authenticate(email = email, password=password)
        
        if user:
            #token creation for the logged in user
            token, _ = Token.objects.get_or_create(user=user)
            return Response(user.getDetails(), status=status.HTTP_200_OK) # type: ignore
        return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)

models.py

class CustomUser(AbstractUser):
   # username = models.CharField(max_length = 25 ,default = 'No name',unique = True)
    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')
    password = models.CharField(max_length = 25,default = "no password")
    
    
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
    
    def getDetails(self):
        return {
            'email': self.email,
            'first_name': self.first_name,
            'last_name': self.last_name
        }

serializers.py

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomUser
        fields = ['id','email','password','first_name','last_name']
        extra_kwargs = {'password': {'write_only': True}}

views.py

class UserLoginAPIView(generics.GenericAPIView):
    """
    An endpoint to authenticate existing users using their email and password.
    """

    permission_classes = [AllowAny]
    serializer_class = LoginSerializer

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

Пытается войти пользователь с теми же учетными данными, которые использовались в процессе регистрации.

Вы сталкиваетесь с фреймворком Django Rest, поэтому вам лучше следовать официальной документации и использовать TokenObtainPairSerializer, но это не страшно. Чтобы создать аутентификацию с нуля в DRF : создайте сериализатор для процесса Login следующим образом :

class LoginSerializer(serializer.Serializer):
    password = serializers.CharField()
    email = serializers.EmailField()

конечно же, вам понадобится CustomUserSerialzier, например, такой :

class CustomUserSerializer(serializers.ModelSerializer):
    """
    Serializer class to serialize CustomUser model.
    """

    class Meta:
        model = User
        fields = ("email", "first_name", "last_name", "id",)

и в файле views.py измените процесс входа в систему следующим образом :

from rest_framework_simplejwt import tokens

class UserLoginAPIView(generics.GenericAPIView):
    """
    An endpoint to authenticate existing users using their email and password.
    """

    permission_classes = (permissions.AllowAny,)
    serializer_class = LoginUserSerializer

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

Надеюсь, это поможет.

Примечание1 : Моя модель и сериализатор выглядят так :

models.py

class AllUser(BaseUserManager):
    def create_user(self, phone, email, password=None, **kwargs):
        if not email:
            raise ValueError('کاربر باید پست الکترونیکی داشته باشد')
        
        if not phone:
            raise ValueError('کاربر باید شماره تلفن داشته باشد')

        user = self.model(
            email=self.normalize_email(email),
            phone=phone,
            **kwargs,
        )
        user.is_active = False
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staff(self, phone, email, password):
        user = self.create_user(
            email=email,
            phone=phone,
            password=password,
        )
        user.is_staff = True
        user.is_active  = False
        user.is_superuser = False        
        user.save(using=self._db)
        return user

    def create_superuser(self, phone, email, password):
        user = self.create_user(
            email=email,
            phone=phone,
            password=password,
        )
        user.is_staff = True
        user.is_active  = True
        user.is_superuser = True        
        user.save(using=self._db)
        return user

class User(AbstractBaseUser, PermissionsMixin):
    phone        = models.CharField(max_length=30, unique=True)
    email        = models.EmailField(unique=True)
    password     = models.CharField(max_length=255, null=True)
    is_locked    = models.BooleanField(default=False)
    is_staff     = models.BooleanField(default=False)    
    is_admin     = models.BooleanField(default=False)
    last_login   = models.DateTimeField(null=True, blank=True)
    created_at   = models.DateTimeField(auto_now_add=True)
    
    USERNAME_FIELD = "phone"
    REQUIRED_FIELDS = ["email"]
    
    objects = AllUser()

    def __str__(self) -> str:
        return self.phone
    
    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

serializers.py

class CustomUserSerializer(serializers.ModelSerializer):
    """
    Serializer class to serialize CustomUser model.
    """

    class Meta:
        model = User
        fields = ("id", "phone", "email")


class UserRegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = User 
        fields = ['phone', 'email', 'password']


class LoginUserSerializer(serializers.Serializer):
    phone    = serializers.CharField()
    password = serializers.CharField()
    
    def validate(self, data):
        user = authenticate(**data)
        if user and user.is_active:
            return user
        raise serializers.ValidationError("Incorrect Credentials")

и мой взгляд на то, что я напечатал выше. проверьте это.

Вернуться на верх