[django] jwt로 토큰키 특정횟수 이상 호출하면 만료되도록 구현하기

최승언·2023년 9월 18일
0

django

목록 보기
15/15
post-thumbnail

요청 횟수가 초과되면 토큰이 만료되도록 구현하려면 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})
profile
작업하다가 막힌부분을 기록하는 곳.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN