无法在 Django Rest Framework 中使用用户令牌和 API 密钥对测试请求进行身份验证

时间:2021-02-20 12:59:13

标签: django django-rest-framework

我的项目对某些端点需要两种身份验证方法:

  1. 使用 this app 的全局 API 密钥。
  2. 使用 DRF 提供的默认令牌的用户身份验证令牌

使用 Postman 或 iOS 应用程序使用 API 时一切正常,但我无法在测试中进行身份验证。用户身份验证工作正常,但全局密钥失败。

这是 Postman 中 HTTP 标头的外观:

X-Api-Key: KEY_VALUE
Authorization: Token TOKEN_VALUE

我尝试使用 shell 中的代码进行验证,并且使用与测试中使用的完全相同的代码进行身份验证工作正常!只有在测试中它失败了,所以我不确定如何进一步调试。

编辑:

您可以看到一个完整的项目 on github

测试输出:

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test (app.tests.MyTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File ".../authtest/app/tests.py", line 21, in test
    self.assertEqual(response.status_code, status.HTTP_200_OK)
AssertionError: 403 != 200

----------------------------------------------------------------------
Ran 1 test in 0.112s

FAILED (failures=1)
Destroying test database for alias 'default'...

当我用 python manage.py shell 打开 shell 并复制并粘贴测试代码时:

>>> from rest_framework.test import (APITestCase, APIRequestFactory, force_authenticate)
>>> from rest_framework import status
>>> from accounts.models import User
>>> from app.views import MyView
>>> user = User.objects.create(email="test@test.com")
>>> user.set_password('1234')
>>> factory = APIRequestFactory()
>>> API_KEY = "KIkKSSz7.ziURxOZv8e66f28eMLYwPNs7eEhrNtYl"
>>> headers = {"HTTP_X_API_KEY": API_KEY}
>>> request = factory.get('/myview', **headers)
>>> force_authenticate(request, user=user)
>>> response = MyView.as_view()(request)
>>> response.status_code
200

也用邮递员作品提出请求。知道这里发生了什么吗?

1 个答案:

答案 0 :(得分:1)

问题是您在测试中传递的硬编码 API_KEY 不是导致状态 403 的有效密钥。我认为原因可能是 django 在运行测试和 djangorestframework-api 时使用了单独的测试数据库- key 使用 APIKey 模型生成 api_key。

您可以通过以下方式确认:

  1. 从 MyView 的权限类中删除 HasAPIKey 并再次运行测试。
  2. 或者通过在测试中将空字符串作为 API_KEY 传递导致相同 您现在遇到的错误。

所以我可能建议生成一个新的有效 api_key 并传递它而不是硬编码的密钥。

在这里,我将分享一个更新的测试文件,说明如何进行测试

from rest_framework.test import (APITestCase, APIRequestFactory, force_authenticate)
from rest_framework import status
from accounts.models import User
from .views import MyView
from rest_framework_api_key.models import APIKey


class MyTests(APITestCase):

    def test(self):
        user = User.objects.create(email="test@test.com")
        user.set_password('1234')
        user.save()
        factory = APIRequestFactory()
        api_key, key = APIKey.objects.create_key(name="my-remote-service")
        headers = {"HTTP_X_API_KEY": key}
        request = factory.get('/myview', **headers)
        force_authenticate(request, user=user)
        response = MyView.as_view()(request)
        self.assertEqual(response.status_code, status.HTTP_200_OK)