了解 JWT 并确认 simplejwt 在测试用例中过期

Understanding JWT and confirm simplejwt expire in testcase

我只是想了解 djangorestframework-simplejwt 过期时间,想知道令牌过期时返回的内容。

为了探索这一点,我在我的 django 项目中编写了一个简单的测试用例,但我似乎无法让过期发生。

views.py

import json
from http import HTTPStatus

from django.http import JsonResponse
from rest_framework.decorators import api_view

from .models import Visitor


@api_view(["POST"])
def visitor_post(request):
    body_unicode = request.body.decode("utf-8")
    if not body_unicode.strip():
        return JsonResponse({"status": HTTPStatus.BAD_REQUEST}, status=HTTPStatus.BAD_REQUEST)

    body = json.loads(body_unicode)
    submitted_datetime = body["submitted_datetime"]

    visitor = Visitor(
        representative_name=body["representative_name"],
        visitor_type=body["visitor_type"],
        visitor_count=body["visitor_count"],
        submitted_datetime=submitted_datetime,
    )
    visitor.save()
    return JsonResponse({"status": HTTPStatus.CREATED}, status=HTTPStatus.CREATED)

目前我的测试用例如下:

tests.py

import datetime
import json
from time import sleep
from http import HTTPStatus
from typing import Optional, Tuple

from accounts.models import CustomUser
from django.urls import reverse
from django.utils import timezone
from django.test import override_settings
from rest_framework.test import APIClient, APITestCase


EXPIRE_WAIT_SECONDS = 5
SIMPLE_JWT_EXPIRE_TEST_SETTINGS = {
    "ACCESS_TOKEN_LIFETIME": datetime.timedelta(seconds=EXPIRE_WAIT_SECONDS),
    "REFRESH_TOKEN_LIFETIME": datetime.timedelta(days=14),
    "ROTATE_REFRESH_TOKENS": True,
    "BLACKLIST_AFTER_ROTATION": False,
    "ALGORITHM": "HS256",
    "SIGNING_KEY": 'kkdkasjf;a',
    "VERIFYING_KEY": None,
    "AUTH_HEADER_TYPES": ("JWT",),
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
}


class ViewsTestCase(APITestCase):
    def setUp(self):
        self.valid_user = CustomUser(last_name="user", first_name="valid", username="validuser", email="validuser@email.com")
        self.valid_user_password = "mysecretpassword"
        self.valid_user.set_password(self.valid_user_password)
        self.valid_user.save()
        self.apiclient = APIClient()

    def _get_jwt_token(self, username: Optional[str] = None, password: Optional[str] = None) -> Tuple[str, str]:
        if not username:
            username = self.valid_user.username
        if not password:
            password = self.valid_user_password
        body = {"username": username, "password": password}
        url = reverse("token_obtain_pair")
        response = self.apiclient.post(url, data=body, format="json")
        self.assertEqual(response.status_code, 200)
        token_data = json.loads(response.content)
        return token_data["access"], token_data["refresh"]

    @override_settings(SIMPLE_JWT=SIMPLE_JWT_EXPIRE_TEST_SETTINGS)
    def test_visitor_post_token_expire(self):
        access_token, _ = self._get_jwt_token()

        now = timezone.now()
        data = {
            "representative_name": "Somename",
            "visitor_count": 1,
            "submitted_datetime": now.isoformat(),
        }
        sleep(EXPIRE_WAIT_SECONDS + 1)
        self.apiclient.credentials(HTTP_AUTHORIZATION=f"JWT {access_token}")
        url = "/visitors/"
        response = self.apiclient.post(url, data=data, format="json")
        self.assertEqual(response.status_code, HTTPStatus.UNAUTHORIZED)

我希望这会导致某种授权错误,例如 401 之类的,但它似乎仍会创建受保护的视图。

self.assertEqual(response.status_code, HTTPStatus.UNAUTHORIZED)AssertionError: 201 != HTTPStatus.UNAUTHORIZED: 401

为什么令牌不会过期?或者,如何使令牌过期?

可能是我理解的不正确

我的理解是,当 ACCESS_TOKEN_LIFETIME 过期时,您将无法再使用 access_token,需要使用 refresh 令牌获取新令牌。对吗?

插件必须在启动时获取设置并实例化其对象。在运行时,它不会再次读取设置,因此覆盖它们是没有用的。

正如您所做的那样,测试此功能的正确方法是使用单独的设置模块进行测试并将插件配置放在那里。

上述解决方案可以正常工作,但是测试过期会导致其他使用令牌的测试失败,因为它们都会过期。

你也可以按照这个解决方案 Unit Testing JWT token exipiration: Django REST