Django Rest Framework APIClient login не работает
У меня есть тестовая функция для проверки того, может ли пользователь войти в систему или нет. Я использую APIClient от DRF и вхожу в систему. Когда я делаю запрос get к защищенной конечной точке API, я получаю 401 ответ.
Я попытался напечатать:
print(client.login(username='instructor', password='asdf'))
И он возвращает True, что означает, что пользователь найден и вошел в систему.
Но все равно, когда я это делаю:
response = client.get(reverse('recommend-list'))
Я получаю 401.
Вот моя тестовая функция:
def test_user_authentication(self):
client = APIClient()
user_data = {
'username': 'instructor',
'email': 'myemail@example.com',
'password': 'asdf'
}
client.post(reverse('user-list'), user_data, format='json')
self.assertTrue(User.objects.filter(username='instructor').exists())
print(client.login(username='instructor', password='asdf'))
response = client.get(reverse('recommend-list'))
self.assertEqual(response.status_code, 200)
Вот как я создаю нового пользователя:
class UserViewSet(viewsets.ViewSet):
def create(self, request):
serializer = UserSerializer(data=request.data)
User = get_user_model()
if serializer.is_valid():
validated_data = serializer.validated_data
try:
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password']
)
return Response({'id': user.id, 'username': user.username}, status=status.HTTP_201_CREATED)
except IntegrityError:
return Response({'error': 'Username is already taken.'}, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Делаю запрос на получение сюда:
class RecommendViewSet(viewsets.GenericViewSet):
authentication_classes = [BasicAuthentication]
permission_classes = [IsAuthenticated]
def list(self, request):
user_id = request.user.id
movies = recommend_movies_for_user(user_id)
return Response({"message": movies}, status=status.HTTP_200_OK)
Правильно, я думал, что это может быть простая проблема с хэшированием, но я ошибался.
Проблема в том, что вы используете BasicAuthentication для аутентификации учетных данных, которая пытается найти имя пользователя и пароль, которые должны присутствовать в запросе headers. Таким образом, вам необходимо закодировать учетные данные и правильно задать параметры headers:
class TestUser(TestCase):
def test_user_authentication(self):
client = APIClient()
user_data = {
"username": "instructor",
"email": "myemail@example.com",
"password": "asdf",
}
client.post(reverse("user-list"), user_data, format="json")
get_user_model().objects.get(username="instructor")
# Encode credentials and set the header
cstring = f"{user_data["username"]}:{user_data["password"]}".encode("utf-8")
c=base64.b64encode(cstring)
client.credentials(HTTP_AUTHORIZATION=f"Basic {c.decode()}")
response = client.get(reverse("recommend-list"))
self.assertEqual(response.status_code, 200)
С другой стороны, то, что делает .login, это присоединяет User к сессии с помощью метода authenticate. Поэтому, если вы используете SessionAuthentication, ваш оригинальный код будет работать просто отлично.