使用 django rest 框架和 django oauth 工具包在单元测试中进行 oAuth 身份验证
Posted
技术标签:
【中文标题】使用 django rest 框架和 django oauth 工具包在单元测试中进行 oAuth 身份验证【英文标题】:oAuth authentication in unit tests using django rest framework and django oauth toolkit 【发布时间】:2015-07-24 08:08:50 【问题描述】:如何为需要 oAuth 身份验证的 API 端点编写单元测试?
仅将 oAuth 令牌添加到请求标头是行不通的(可能是因为测试数据库不是持久的)。将夹具加载到数据库中也无济于事。
我正在使用 django-rest-framework 和 django-oauth-toolkit。
我的 test.py 代码:
class Com_jm_Test(TestCase):
fixtures=['oauth.json',]
print 'test com jm'
multi_db=True
def test_list_job(self):
self.client=Client(HTTP_AUTHORIZATION='Bearer 0cx2G9gKm4XZdK8BFxoWy7AE025tvq')
response=self.client.get('/com-jm/jobs/')
self.assertEqual(response.status_code,200)
结果:
AssertionError: 401 != 200
【问题讨论】:
【参考方案1】:查看 DRF 的测试文档,特别是 the chapter on "Forcing authentication"。从这些文档中:
例如,当强制使用令牌进行身份验证时,您可能会执行以下操作:
user = User.objects.get(username='olivia') request = factory.get('/accounts/django-superstars/') force_authenticate(request, user=user, token=user.token)
【讨论】:
我之前尝试过,但是当我将用户的查询集放入测试用例时,它总是给我一个错误消息,找不到符合查询集的数据 您能详细说明一下吗?您使用的是什么查询集?并且您是否在测试数据库中加载了测试用户数据? fixture_dirs 似乎有问题,我正在尝试解决这个问题,有没有其他方法可以在不强制验证的情况下进行测试?因为我进行单元测试的目的是显示只有请求有令牌可以访问我的API,非常感谢 如果您想测试未经授权的用户是否无法访问该视图,只需测试HTTP 401 Unauthorized
响应即可。 self.assertEqual(response.status_code, 401
将完成这项工作。当然,您还应该测试授权用户是否可以访问将我们带回到原始问题的视图:)【参考方案2】:
根据您的应用程序,您可能希望从 django-oauth-toolkit 修补此函数,以便为您的客户端返回任意访问令牌:
oauth2_provider.ext.rest_framework.OAuth2Authentication.authenticate
因为这是 django-rest-framework 中默认用于身份验证的方法。
【讨论】:
【参考方案3】:这样做:
-
创建用户
创建应用程序
创建令牌
def __create_authorization_header(token):
return "Bearer 0".format(token)
def __create_token(self, user):
app = Application.objects.create(
client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
redirect_uris='https://www.none.com/oauth2/callback',
name='dummy',
user=user
)
access_token = AccessToken.objects.create(
user=user,
scope='read write',
expires=timezone.now() + timedelta(seconds=300),
token='secret-access-token-key',
application=self.app
)
return access_token
user = User(username='dummy', email='dummy@geneu.com')
user.save()
self.user = user
token = __create_authorization_header(__create_token(user))
response=self.client.get('/com-jm/jobs/', format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.status_code,200)
当然,这必须适应您的需求,但这就是想法。对于此类未来的问题(当您在文档中没有找到足够的信息来归档您的目标时)我建议您查看源代码。例如,在这种情况下,您可以在工具包库的测试中找到如何执行此操作。 (django-oauth-toolkit/oauth2_provider/tests/test_authorization_code.py)
【讨论】:
【参考方案4】:我也遇到了同样的问题。这是我的解决方案。
DRF 提供APIClient
用于提出请求。
APIClient
类支持与 Django 的标准客户端类相同的请求接口。这意味着标准的.get(), .post(), .put(), .patch(), .delete(), .head()
和.options()
方法都可用。
还提供credentials
方法可用于设置标头,然后将包含在测试客户端的所有后续请求中。
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token AB7JSH^4454')
DRF docs
创建 Oauth 令牌
创建和获取用户
token = user.oauth2_provider_accesstoken.create(expires='expire_date', token='token')
使用 APIClient 设置 Ouath 令牌
client = APIClient()
client.credentials(Authorization='Bearer '.format(token))
client.get(reverse('accounts_api:profile'))
我们可以设置默认内容类型
REST_FRAMEWORK +=
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
Git Hub Link for Source
【讨论】:
【参考方案5】:这是结合@Deepak Kabbur 和@Daniel Albarral 的答案的改进。
派生 DRF 的 APIClient 的子类,以使用属于给定用户的 OAuth2 应用程序设置凭据:
import rest_framework.test
from oauth2_provider.models import Application, AccessToken
class APIClient(rest_framework.test.APIClient):
def credentials(self, user: User, application_name: str):
# Create or update OAuth2 application.
app, created = Application.objects.update_or_create(
defaults='name': application_name,
client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
redirect_uris='https://www.none.com/oauth2/callback',
name=application_name,
user=user)
# Create or update the token, and set it in a default request header.
now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
access_token, created = AccessToken.objects.update_or_create(
defaults='user': user, 'application': app,
user=user,
scope='read write',
expires=now + datetime.timedelta(seconds=300),
token='secret-access-token-key',
application=app)
super().credentials(HTTP_AUTHORIZATION='Bearer '.format(access_token))
使用派生的 APIClient 创建测试用例(您必须至少使用 APITestCase,因为设置凭据的过程需要访问数据库):
class TestAPI(rest_framework.test.APITestCase):
client_class = APIClient
def test_000_authenticate(self):
self.client.credentials(ACME_MASTER_ADMIN, 'my-app')
response = self.client.get('/api/v1/company'), format='json')
assert response.status_code == 200
【讨论】:
以上是关于使用 django rest 框架和 django oauth 工具包在单元测试中进行 oAuth 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有 Django Rest 框架的 React 前端使用 Django 用户组和权限
django.test.client 上的 Django rest 框架导入错误