使用 APIRequestFactory 测试基于令牌的身份验证的正确方法是啥?

Posted

技术标签:

【中文标题】使用 APIRequestFactory 测试基于令牌的身份验证的正确方法是啥?【英文标题】:What's the proper way to test token-based auth using APIRequestFactory?使用 APIRequestFactory 测试基于令牌的身份验证的正确方法是什么? 【发布时间】:2014-10-21 11:05:27 【问题描述】:

对我的端点的查询工作正常(只要我传递一个有效的令牌),它返回我的响应数据的 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)

在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:身份验证失败”。因为没有在请求中设置令牌。

有没有合适的方法在我的测试的请求标头中设置它或重构我首先使用它的方式?

【问题讨论】:

【参考方案1】:

我找到了让测试通过的方法,但如果您对如何处理这些问题有更好的了解,请发布。

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

改了上面两行测试后,好像可以正确的基于token进行认证了。

【讨论】:

【参考方案2】:

我想测试身份验证功能本身,因此无法选择强制身份验证。

正确传递令牌的一种方法是使用您已经导入的APIClient。

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

这会将您给定的令牌设置到请求标头中,并让后端决定它是否有效。

【讨论】:

client.get 不返回响应对象 @frei 是的。我刚刚使用当前版本再次对其进行了测试,它返回了一个在django.http.response 中定义的对象,因此无论是名称还是它在此代码 sn-p 中所做的事情都是一个“响应”。 特别是在我的测试中,我遵循了 DRF 的快速入门,使用该 sn-p 进行了一次测试,并检查了 type(response)。它给了我django.http.response.HttpResponseNotFound,这对于请求的测试来说已经足够“响应”了。【参考方案3】:

很抱歉挖掘了这个旧线程,但如果有人使用 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 tests

【讨论】:

self.client = APIClient() 这行不是必需的,因为您继承自 APITestCase 已经拥有它。【参考方案4】:

使用APITestCase 的内置方法来force_authentication 的更简单方法是:

class Test(APITestCase):
    def setUp(self):
        user1 = User.objects.create_user(username='foo')
        self.client.force_authenticate(user=user1) # self.client is from APITestCase

    ... the rest of your tests ...

【讨论】:

以上是关于使用 APIRequestFactory 测试基于令牌的身份验证的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

带有版本控制的 DRF 测试视图:版本化 url 检索

何时使用基于属性的测试?

使用 Mocha 进行测试:基于 Promise 的测试不会自行运行?

构建一个测试,该测试使用在 localhost 上运行的基于 Spring 的 REST API URL 进行测试

使用 Web 服务对服务器进行负载测试是不是与基于负载测试场景相同?

在测试中使用基于 UserPart 的部件