django - 无法在 Django Rest Framework 中同时使用用户令牌和 API 密钥验证测试请求
问题描述
我的项目需要对某些端点使用两种身份验证方法:
- 使用此应用程序的全局 API 密钥。
- 使用 DRF 提供的默认用户身份验证令牌
使用 Postman 或 iOS 应用程序使用 API 时一切正常,但我无法在我的测试中进行身份验证。用户身份验证工作正常,但全局密钥失败。
这是 Postman 中 HTTP 标头的外观:
X-Api-Key: KEY_VALUE
Authorization: Token TOKEN_VALUE
我尝试使用 shell 中的代码进行试验,并且使用测试中使用的完全相同的代码进行身份验证工作正常!只有在测试中它才会失败,所以我不确定如何进一步调试。
编辑:
你可以在 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
并复制并粘贴测试代码时:
>>> 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
也向邮递员提出请求。知道这里发生了什么吗?
解决方案
问题是API_KEY
您在测试中传递的硬编码不是导致状态 403 的有效密钥。我认为原因可能是 django 在运行测试时使用了单独的测试数据库,而 djangorestframework-api-key 使用 APIKey 模型生成 api_key。
您可以通过以下方式确认:
- 从 MyView 中的权限类中删除 HasAPIKey 并再次运行测试。
- 或通过在您的测试中将空字符串作为 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)
推荐阅读
- ios - IGListKit 是如何更新 sectionHeader 的?
- reactjs - 如何为 ReactJS 使用 CSS 编辑器?
- spring-boot - 带有两个 Spring Boot 应用程序的 Docker Compose 得到“消息”:“对 \”http://127.0.0.1:8010/...的 GET 请求出现 I/O 错误:连接被拒绝”
- vue.js - Apexcharts:是否可以显示给定系列的子集?默认情况下,我只需要关注一个系列的最后 5 个元素......而不是整个系列
- excel - 如何更改 ListBox 中的显示值?行源
- java - Spring @Async 中的默认值是什么?
- excel - 在 EXCEL 中将日期时间 (yyyy-mm-dd hh:mm:ss) 格式转换为秒
- hibernate - 两个表中带有休眠的主键
- angular - 之后如何解决推送值及其替换的问题?
- sql - 将多个表关联到一个表 [SQL - Oracle 12c]