简体   繁体   English

无法使用 Django Rest 框架中的用户令牌和 API 密钥验证测试请求

[英]Cannot Authenticate Test Requests with Both User Token and API Key in Django Rest Framework

My project requires two authentication methods for some endpoints:我的项目需要对某些端点使用两种身份验证方法:

  1. A global API key using this app .使用 此应用程序的全局 API 密钥。
  2. A user authentication token using the default one provided by DRF使用 DRF 提供的默认用户身份验证令牌

All works fine when working with the API using Postman or an iOS app, but I couldn't make the authentication work in my tests.使用 Postman 或 iOS 应用程序使用 API 时,一切正常,但我无法在我的测试中进行身份验证。 The user auth works fine, but the global key fails.用户身份验证工作正常,但全局密钥失败。

This is how the HTTP headers look in Postman:这是 HTTP 接头在 Postman 中的外观:

X-Api-Key: KEY_VALUE
Authorization: Token TOKEN_VALUE

I tried to experiment with the code in the shell and authentication worked fine using the exact same code used in the test.我尝试使用 shell 中的代码进行试验,并且使用测试中使用的完全相同的代码进行身份验证工作正常。 Only in the tests it fails so I'm not really sure how to debug this further.只有在测试中它才会失败,所以我不确定如何进一步调试。

Edit:编辑:

You can see a complete project on github .你可以在 github 上看到一个完整的项目。

Test output:测试 output:

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'...

When I open the shell with python manage.py shell and copy and paste the test code:当我打开 shell 和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

Also making the request with postman works.也可以使用 postman 提出请求。 Any idea what's going on here?知道这里发生了什么吗?

The problem is the hardcoded API_KEY you are passing in your test which is not a valid key resulting in status 403. I think the reason might be django uses a separate test database when running tests and djangorestframework-api-key uses APIKey model to generate api_key.问题是您在测试中传递的硬编码API_KEY这不是导致状态 403 的有效密钥。我认为原因可能是 django 在运行测试时使用单独的测试数据库,而 djangorestframework-api-key 使用 APIKey model 生成 api_key .

You can confirm this by:您可以通过以下方式确认:

  1. Removing HasAPIKey from permission classes in MyView and running test again.从 MyView 中的权限类中删除 HasAPIKey 并再次运行测试。
  2. or by passing empty string as API_KEY in your test resulting in same error you are getting now.或通过在您的测试中将空字符串作为 API_KEY 传递,从而导致您现在遇到相同的错误。

so what i might suggest is generating a new valid api_key and passing it instead of hardcoded key.所以我可能建议生成一个新的有效 api_key 并传递它而不是硬编码密钥。

Here i am sharing an updated test file of how you can carry out your test在这里,我将分享如何进行测试的更新测试文件

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Django rest框架中验证API请求(由匿名用户)? - How do I authenticate API requests (by anonymous user) in Django rest framework? Api 密钥和 Django Rest Framework 身份验证令牌 - Api key and Django Rest Framework Auth Token 使用django rest框架为每次登录使用新令牌对用户进行身份验证 - Working with django rest framework to authenticate a user with new token for every login 使用appid和访问令牌对Django rest框架进行身份验证? - authenticate django rest framework with appid and access token? 如何在 django rest 框架中传递用户令牌进行 API 测试? - How to pass the user token for API testing in django rest framework? 测试API密钥以使用Django Rest Framework和TokenAuthentication返回模拟数据 - Test API Key to return mock data with Django Rest Framework and TokenAuthentication 如何对 Django rest 框架请求进行单元测试? - How to unit test Django rest framework requests? 每个用户请求的Django Rest Framework指标 - Django Rest Framework metrics per user requests 使用MongoEngine用户进行Django Rest Framework令牌认证 - Django Rest Framework Token Authentication with MongoEngine User 用于 Django REST 的 JSON Web 令牌不会对用户数据库进行身份验证 - JSON Web Token for Django REST won't authenticate to user database
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM