如何使用Django-oauth-toolkit进行身份验证,使用Django-rest-framework测试API端点

25
我有一个Django-rest-framework的视图集/路由器来定义API端点。该视图集定义如下:

I have a Django-rest-framework viewset/router to define an API endpoint. The viewset is defined as such:


class DocumentViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]
    model = Document

路由器被定义为

router = DefaultRouter()
router.register(r'documents', viewsets.DocumentViewSet)

使用url模式url(r'^api/', include(router.urls))

我可以通过获取正确的访问令牌并将其用于授权在浏览器/通过curl轻松地访问此端点。但是,如何针对此端点编写测试不清楚。

以下是我尝试过的内容:

class DocumentAPITests(APITestCase):
    def test_get_all_documents(self):
        user = User.objects.create_user('test', 'test@test.com', 'test')
        client = APIClient()
        client.credentials(username="test", password="test")
        response = client.get("/api/documents/")
        self.assertEqual(response.status_code, 200) 

使用client.get()调用时,收到HTTP 401响应失败。在DRF中使用django-oauth-toolkit进行oauth2身份验证的正确API端点测试方法是什么?

3个回答

31

在编写测试时,您应该尽可能从测试本身中提取任何未测试的内容,通常将任何设置代码放在测试的setUp方法中。在涉及 OAuth 的 API 测试的情况下,这通常包括测试用户、OAuth 应用程序和活动访问令牌。

对于django-oauth-toolkit和其他 Django 应用程序,我总是建议查看测试以了解它们如何执行。这使您可以避免进行不必要的 API 调用,特别是对于 OAuth 等多部分过程,只创建所需的少数模型对象。

def setUp(self):
    self.test_user = UserModel.objects.create_user("test_user", "test@user.com", "123456")

    self.application = Application(
        name="Test Application",
        redirect_uris="http://localhost",
        user=self.test_user,
        client_type=Application.CLIENT_CONFIDENTIAL,
        authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
    )
    self.application.save()

def test_revoke_access_token(self):
    from datetime import datetime
    from django.utils import timezone

    tok = AccessToken.objects.create(
        user=self.test_user, token='1234567890',
        application=self.application, scope='read write',
        expires=timezone.now() + datetime.timedelta(days=1)
    )

接下来,您只需要使用生成的令牌进行身份验证。您可以通过注入Authorization标头来实现此操作,或者您可以使用Django REST Framework提供的force_authenticate方法


1
没错,我漏掉了创建访问令牌的步骤,而且注入令牌到请求中也不是很清楚。谢谢! - Jim
这正是我一直在寻找的。非常感谢! - Danilo Prado

5
我使用了相同的OAuth2库, 对我来说这个库很有效。
from oauth2_provider.settings import oauth2_settings
from oauth2_provider.models import get_access_token_model, 
get_application_model
from django.contrib.auth import get_user_model
from django.utils import timezone
from rest_framework.test import APITestCase

Application = get_application_model()
AccessToken = get_access_token_model()
UserModel = get_user_model()

class Test_mytest(APITestCase):

    def setUp(self):

        oauth2_settings._SCOPES = ["read", "write", "scope1", "scope2", "resource1"]

        self.test_user = UserModel.objects.create_user("test_user", "test@example.com", "123456")

        self.application = Application.objects.create(
                                                name="Test Application",
                                                redirect_uris="http://localhost http://example.com http://example.org",
                                                user=self.test_user,
                                                client_type=Application.CLIENT_CONFIDENTIAL,
                                                authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
                                            )

        self.access_token = AccessToken.objects.create(
                                                    user=self.test_user,
                                                    scope="read write",
                                                    expires=timezone.now() + timezone.timedelta(seconds=300),
                                                    token="secret-access-token-key",
                                                    application=self.application
                                                )
        # read or write as per your choice
        self.access_token.scope = "read"
        self.access_token.save()

        # correct token and correct scope
        self.auth =  "Bearer {0}".format(self.access_token.token)

    def test_success_response(self):

        url = reverse('my_url',)

        # Obtaining the POST response for the input data
        response = self.client.get(url, HTTP_AUTHORIZATION=self.auth)

        # checking wether the response is success
        self.assertEqual(response.status_code, status.HTTP_200_OK)

现在一切都将按预期运作。希望这对您有所帮助。谢谢。


0
from oauth2_provider.models import (
get_access_token_model,
get_application_model,
get_id_token_model,
get_refresh_token_model,
)

 class TestOauth(APITestCase):
    def setUp(self):
            """ create and register user """
            self.test_user = User.create..

    def test_oauth_application_and_tokens_add(self):
        print(self.test_user, self.test_user.id)
        """Applications"""
        Application = get_application_model()
        app = Application()
        app.name = "test"
        app.client_type = "confidential"
        app.authorization_grant_type = "password"
        app.user_id = self.test_user.id
        app.save()

        # client_id:
        print("Application Client ID: ", app.client_id)

        # client_secret:
        print("Application Client SECRET: ", app.client_secret)

        """Access Token"""
        AccessToken = get_access_token_model()
        token = AccessToken()
        token.user_id = self.test_user.id
        token.scope = "read write"
        token.expires = timezone.now() + timezone.timedelta(seconds=300)
        token.token = "secret-access-token-key"
        token.application = app
        token.save()

        # token
        print("Access Token: ", token)

        self.auth = "Bearer {0}".format(token.token)

        """ ID Token """
        IDToken = get_id_token_model()
        idt = IDToken()
        idt.user_id = self.test_user.id
        idt.application = app
        idt.expires = timezone.now() + timezone.timedelta(days=10)
        idt.scope = "read write"
        idt.save()

        # id token - returns jti token - successfull
        print("ID Token: ", idt)

        """ Refresh Token """
        RefreshToken = get_refresh_token_model()
        refr = RefreshToken()
        refr.user_id = self.test_user.id
        refr.application = app
        refr.token = "statictoken"  # The token is issued statically.
        refr.access_token = (
            token  # The access token must not have been used before.
        )
        refr.revoked = timezone.now() + timezone.timedelta(days=10)
        refr.save()

        # refresh token
        print("Refresh Token: ", refr)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接