Python Django Rest框架JWT单元测试
我将DRF与JWT包一起用于身份验证。现在,我正在尝试编写一个单元测试,用JWT令牌对自己进行身份验证。无论我如何尝试,我都无法让测试API客户机通过JWT进行身份验证。如果我对API客户机(在我的例子中是Postman)也这样做,那么一切都会正常工作 这是测试用例:Python Django Rest框架JWT单元测试,python,django,django-rest-framework,jwt,Python,Django,Django Rest Framework,Jwt,我将DRF与JWT包一起用于身份验证。现在,我正在尝试编写一个单元测试,用JWT令牌对自己进行身份验证。无论我如何尝试,我都无法让测试API客户机通过JWT进行身份验证。如果我对API客户机(在我的例子中是Postman)也这样做,那么一切都会正常工作 这是测试用例: from django.urls import reverse from rest_framework.test import APITestCase from rest_framework_jwt.settings import
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework_jwt.settings import api_settings
from backend.factories import member_factory
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class MemberTests(APITestCase):
def test_get_member(self):
member = member_factory()
payload = jwt_payload_handler(member.user)
token = jwt_encode_handler(payload)
self.client.credentials(Authorization='JWT {0}'.format(token))
response = self.client.get(reverse('member-detail', kwargs={'pk': member.pk}))
assert response.status_code == 200
但我总是得到一个401身份验证凭据,但没有提供
在response.request
中,我看到令牌在那里,我想它只是没有被应用
如果我重写测试以使用rest\u framework.test.RequestsClient
,并实际将其发送到URL,它就会工作
有什么帮助吗
注意:我知道
force_authenticate()
和,但我希望我的单元测试能够像API客户端在生产中一样访问API。尝试为此测试设置一个新的APIClient。我自己的测试就是这样的
def test_api_jwt(self):
url = reverse('api-jwt-auth')
u = user_model.objects.create_user(username='user', email='user@foo.com', password='pass')
u.is_active = False
u.save()
resp = self.client.post(url, {'email':'user@foo.com', 'password':'pass'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
u.is_active = True
u.save()
resp = self.client.post(url, {'username':'user@foo.com', 'password':'pass'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertTrue('token' in resp.data)
token = resp.data['token']
#print(token)
verification_url = reverse('api-jwt-verify')
resp = self.client.post(verification_url, {'token': token}, format='json')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
resp = self.client.post(verification_url, {'token': 'abc'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='JWT ' + 'abc')
resp = client.get('/api/v1/account/', data={'format': 'json'})
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
client.credentials(HTTP_AUTHORIZATION='JWT ' + token)
resp = client.get('/api/v1/account/', data={'format': 'json'})
self.assertEqual(resp.status_code, status.HTTP_200_OK)
我有类似的问题,随信附上我的解决方案,只是为了有更多的代码进行比较(tests.py)
受@dkarchmer启发,这是我的代码。
我使用的是自定义用户模型,电子邮件用于身份验证。
注意使用
电子邮件
字段进行身份验证请求。
如果我使用用户名
,则响应为400\u BAD\u请求
。
401\u UNAUTHORIZED
通常表示凭据不正确或用户未激活
def测试_异常(自身):
User=get\u User\u model()
电子邮件user@test.com'
密码='userpass1'
用户名='user'
user=user.objects.create\u user(
用户名=用户名,电子邮件=电子邮件,密码=密码)
user.is_active=False
user.save()
获取url=reverse('token\u获取\u对')
resp=self.client.post(
获取url,{'email':电子邮件,'password':password},format='json')
self.assertEqual(分别为status\u代码、status.HTTP\u 401\u未经授权)
user.is_active=True
user.save()
resp=self.client.post(
获取url,{'email':电子邮件,'password':password},format='json')
self.assertEqual(分别为status\u代码、status.HTTP\u 200\u OK)
邮递员与您的实际数据库交互。Django使用单独的数据库来运行测试用例。因此,在身份验证测试之前,需要在测试定义中再次创建新的用户记录。希望这能有所帮助。如果您正在使用and和Python 3.6+,则以下答案适用。您需要创建一个fixture,我称之为api\u client
,您需要为现有用户获取令牌
来自django.contrib.auth.models导入用户
从rest\u framework.test导入APIClient
从rest\u framework\u simplejwt.tokens导入RefreshToken
导入pytest
@pytest.fixture
def api_客户端():
user=user.objects.create_user(用户名='john',电子邮件='wwwjs@js.com“,password='js.sj')
client=APIClient()
refresh=RefreshToken.for_用户(用户)
client.credentials(HTTP_AUTHORIZATION=f'Bearer{refresh.access_token})
返回客户端
注意,在上面的fixture中,用户是在那里创建的,但是您可以使用另一个fixture来创建用户并将其传递给这个fixture。关键要素如下所示:
refresh=refreshtToken.for_用户(用户)
这一行允许您按照说明手动创建令牌。拥有该令牌后,您可以使用方法credentials
来设置头,然后测试客户端将在所有后续请求中包含这些头。请注意,refresh.access\u令牌
包含访问令牌
必须在测试中使用此装置,您需要对用户进行身份验证,如以下示例所示:
@pytest.mark.django\u db
def测试您的测试的名称(api客户端):
#在这里添加您的逻辑
url=reverse('your-url')
response=api\u client.get(url)
data=response.data
assert response.status_code==HTTP_200_OK
#你的断言
因为我使用的是django单元测试客户端,所以我刚刚创建了一个简单的基类,其中包含一个承载令牌属性:
import json
from django.test import TestCase
from django.contrib.auth import User
from rest_framework.test import APIClient
from rest_framework_simplejwt.tokens import RefreshToken
class TestCaseBase(TestCase):
@property
def bearer_token(self):
# assuming there is a user in User model
user = User.objects.get(id=1)
client = APIClient()
refresh = RefreshToken.for_user(user)
return {"HTTP_AUTHORIZATION":f'Bearer {refresh.access_token}'}
在我的django单元测试中:
class SomeTestClass(TestCaseBase):
url = "someurl"
def test_get_something(self):
self.client.get(self.url, **bearer_token)
def test_post_something(self):
self.client.post(self.url, data={"key":"value"}, **self.bearer_token)
谢谢不需要新的APIClient,因为
APITestCase
已经有一个。但是HTTP\u授权
成功了!非常感谢。我使用的django rest框架simplejwt也是如此。使用client.credentials(HTTP_AUTHORIZATION='Bearer'…
(而不是AUTHORIZATION='Bearer'…
)后,一切正常!我在resp=self.client.post(url,{'username':'user@foo.com','password':'pass'},format='json')
使用我正确的用户名/密码。我收到了200封邮递员的回复,但使用此代码得到了401封。当我每天运行单元测试时,代码仍然有效。你应该用代码发布一个独立的问题,让别人帮你。我没能让它工作,因为我在中使用了user\u model.objects.create而不是user\u model.objects.create\u user这种情况发生在某人身上。主要区别在于创建用户在保存之前对密码进行哈希运算。你们两个让我开心。感谢Shope这可以帮助@alexei Marinichenko用户是在test\u get\u member()的第一行创建的
谢谢@Christof。请确保密码已加密,以防万一。根据记忆,我遇到了这两个问题。祝你好运。为我完成了工作,正是我所需要的。谢谢!
class SomeTestClass(TestCaseBase):
url = "someurl"
def test_get_something(self):
self.client.get(self.url, **bearer_token)
def test_post_something(self):
self.client.post(self.url, data={"key":"value"}, **self.bearer_token)