요청 횟수가 초과되면 토큰이 만료되도록 구현하려면 Django의 캐시(Cache) 시스템을 사용하여 각 토큰에 대한 요청 횟수를 추적하고 관리해야 합니다.
아래은 settings 코드입니다.
from datetime import timedelta
# 요청 제한 회수
YOUR_REQUEST_LIMIT = 5
SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('Bearer',),
# 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
# 'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
아래는 토큰키를 생성하는 코드입니다:
class TokenObtainView(APIView):
# POST 요청을 처리하는 뷰입니다.
# 클라이언트가 제공한 사용자 인증 정보(username과 password)를 검증하여 유효한 경우, 새로운 JWT 토큰(refresh token과 access token)을 생성하고 반환합니다.
# 유효하지 않은 인증 정보인 경우, 에러 응답을 반환합니다.
# POST 메서드로 api/token/ 엔드포인트에 요청을 보냅니다.
# Body 탭에서 x-www-form-urlencoded 형식으로 username과 password 파라미터를 전달합니다.
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
# Authenticate the user using Django's built-in authenticate() function
user = authenticate(username=username, password=password)
if user is not None:
# 사용자 인증 로직 수행
token_key = f'token:{username}' # 고유한 저장소(캐시 등)에 저장하기 위한 key
# cache.set(token_key, 1, timeout=settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'].total_seconds())
cache.set(token_key, 1, timeout=None)
refresh = RefreshToken.for_user(user)
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
})
else:
return Response({'error': 'Invalid credentials'}, status=400)
아래는 토큰키에 대한 유효성 검사와 요청이 처리될 때마다 request_count를 증가시키고, 설정된 YOUR_REQUEST_LIMIT에 도달하면 토큰을 삭제하여 요청 제한을 구현하는 방법입니다:
class ProtectedView(APIView):
# GET 요청에 대해서만 허용되는 뷰입니다.
# 해당 뷰에 접근하려면 클라이언트가 유효한 JWT 액세스 토큰(access token)을 제공해야 합니다.
# 액세스 토큰이 유효한 경우, 'This is a protected view' 메시지와 함께 성공 응답을 반환합니다.
# 액세스 토큰이 유효하지 않거나 제공되지 않은 경우, 인증 오류 응답이 반환됩니다.
# GET 메서드로 /protected/ 엔드포인트에 요청을 보냅니다.
# Headers 탭에서 Authorization 필드를 추가하고 값으로 "Bearer <access_token>" 형식으로 액세스 토큰(access token) 값을 전달합니다.
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
token_key = f'token:{request.user.username}'
request_count = cache.get(token_key)
if request_count is None:
cache.set(token_key, 1)
request_count = 1
else:
request_count += 1
cache.set(token_key, request_count)
if request_count > settings.YOUR_REQUEST_LIMIT:
# cache.delete(token_key)
return Response({'error': 'Token expired'}, status=401)
content = {'message': 'This is a protected view'}
return Response(content)
마지막으로 request_count를 확인하는 코드입니다.
class RequestCountView(APIView):
# 이 뷰는 인증된 사용자에게만 허용되며, 해당 사용자의 request_count 값을 반환합니다.
# 해당 뷰에 접근하려면 클라이언트가 유효한 JWT 액세스 토큰(access token)을 제공해야 합니다.
# 요청마다 토큰 키(token:<username>)에서 request_count 값을 조회하고, 값이 존재하지 않으면 오류 응답(404 Not Found)을 반환합니다.
# 그렇지 않은 경우에는 { 'request_count': <count> } 형식의 응답을 반환합니다.
def get(self, request):
token_key = f'token:{request.user.username}'
request_count = cache.get(token_key)
if request_count is None:
return Response({'error': 'No request count found'}, status=404)
return Response({'request_count': request_count})