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")
и мой взгляд на то, что я напечатал выше. проверьте это.