Каков правильный способ тестирования аутентификации на основе токенов с помощью APIRequestFactory?

запрос к моей конечной точке работает нормально (пока я передаю ему допустимый токен), он возвращает представление json моих данных ответа.

код в api службы, который вызывает мою конечную точку, передавая токен аутентификации в заголовке:

headers = {'content-type': 'application/json',
           'Authorization': 'Token {}'.format(myToken)}
url = 'http://localhost:8000/my_endpoint/'
r = session.get(url=url, params=params, headers=headers)

In views.py, у меня есть декоратор метода, который обертывает метод отправки в представлении (viewsets.ReadOnlyModelViewSet):

def login_required(f):
    def check_login_and_call(request, *args, **kwargs):
        authentication = request.META.get('HTTP_AUTHORIZATION', b'')
        if isinstance(authentication, str):
            authentication = authentication.encode(HTTP_HEADER_ENCODING)
        key = authentication.split()
        if not key or len(key) != 2:
            raise PermissionDenied('Authentication failed.')
        user, token = authenticate_credentials(key[1])
        return f(request, *args, **kwargs)
    return check_login_and_call

Я пытаюсь написать тест для аутентификации запроса с помощью токен:

from rest_framework.authtoken.models import Token
from rest_framework.test import APIRequestFactory
from rest_framework.test import APITestCase
from rest_framework.test import force_authenticate

class EndpointViewTest(APITestCase):
    def setUp(self):
        self.factory = APIRequestFactory()
        self.user = User.objects.create_user(
            username='user@foo.com', email='user@foo.com', password='top_secret')
        self.token = Token.objects.create(user=self.user)
        self.token.save()

    def test_token_auth(self):
        request = self.factory.get('/my_endpoint')
        force_authenticate(request, token=self.token.key)
        view = views.EndpointViewSet.as_view({'get': 'list'})
        response = view(request)
        self.assertEqual(response.status_code, 200)
        json_response = json.loads(response.render().content)['results']

по какой-то причине я не могу получить запрос на правильную передачу маркера для этого теста. Использование force_authenticate, похоже, не изменяет заголовок, который я использую для проверки токена. Текущий вывод вызывает " PermissionDenied:ошибка аутентификации.- потому что жетон не устанавливается на запрос.

есть ли способ, чтобы установить это в заголовке запроса в мой тест или переработать способ я использую его в первую очередь?

3 ответов


Я нашел способ пройти тест, но, пожалуйста, напишите, если у вас есть лучшее представление о том, как справиться с этим.

request = self.factory.get('/my_endpoint', HTTP_AUTHORIZATION='Token {}'.format(self.token))
force_authenticate(request, user=self.user)

после изменения вышеуказанных двух строк теста он, похоже, аутентифицируется на основе маркера правильно.


извините за выкапывание этой старой нити, но если кто-то использует APIClient() для выполнения своих тестов вы можете сделать следующее:

from rest_framework.test import APITestCase
from rest_framework.test import APIClient
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User


class VehicleCreationTests(APITestCase):

    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_superuser('admin', 'admin@admin.com', 'admin123')
        self.token = Token.objects.create(user=self.user)

    def testcase(self):
        self.client.force_login(user=self.user)
        response = self.client.post('/api/vehicles/', data=vehicle_data, format='json', HTTP_AUTHORIZATION=self.token)
        self.assertEqual(response.status_code, 201)

действительно хороший ресурс, который я использовал, чтобы придумать это Django-rest-framework-JWT тесты


Я хотел проверить саму функцию аутентификации, поэтому принудительная аутентификация не является опцией.

один из способов правильно передать токен-использовать APIClient, который вы уже импортировали.

client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = client.get('/api/vehicles/')

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