본문 바로가기

TIL

[TIL 2024. 05. 01] DRF 개인과제 오류수정(2)

 

[TIL 2024. 04. 30] DRF 개인과제 오류수정

이번 drf개인과제에서는 simplejwt를 auth에 사용하고 있다. 그런데 로그아웃 코드를 작성했는데, 계속 오류가 발생했다.당시에 작성한 코드는 다음과 같았다.  "logout/" url경로로 들어오면 프로젝

oneday180.tistory.com

 

이 글은 위의 글과 이어진다.

 

위 글에서는 TokenBlacklistView로 로그아웃을 구현하고, 오류를 해결했다고 작성했었는데 위 TIL을 작성한 이후에 로그아웃 뷰에 대해 코드수정을 진행했다.

 

추가적으로 코드를 수정한 이유는 다음과 같다.

  • 로그아웃이란 로그인을 전제로 하는 것인데, access token을 req header를 통해 전달하지 않아도 로그아웃이 실행되는 점은 오류가 아닌가?
  • 로그아웃이 성공하면 message가 뜨면 좋겠다!

이러한 이유로 TokenBlacklistView를 상속하는 LogoutAPIView를 새롭게 작성했다.

 

최초에 작성한 LogoutAPIView최초에 작성한 LogoutAPIView

 


permission_classes를 추가한 후: 오류 메시지

 

 

 

LogoutAPIView에서는 IsAuthenticated를 설정해주는 것과 Response에 message를 넣어주는 것 말고는 아무것도 손대지 않았다.

 

"permission_classes"를 주석처리하면 로그아웃 메시지는 물론이고 블랙리스트에도 refresh token이 잘 추가(=로그아웃)되었다. 즉, 오류의 직접적인 원인은 permission_classes였다. (오류메시지에서도 추론이 가능하지만..)

 

IsAuthenticated를 사용하는 다른 view들(이를테면 ProfileView 등)에서는 인증과 관련된 아무런 문제도 없이 기능이 정상적으로 실행되었다 근데 왜 유독 LogoutAPIView에서만 이런 문제가 발생하는지를 알지 못해서 난항을 겪었다.

 

LogoutAPIView가 TokenBlacklistView를 상속받고 있는만큼, super()의 post()가 호출되기 전에 refresh token을 만료(expire)시키는 다른 로직이 있나 소스코드를 타고 들어가서 봐도 별다른 문제의 실마리를 찾지 못했다.


 

그러던 중에 나와 동일한 문제를 겪었다는 이의 issue를 튜터님의 도움으로 찾을 수 있었다.

 

 

Setting permission_classes to IsAuthenticated results in 403 Forbidden error when extending TokenViewBase · Issue #366 · jazzb

I am trying to add logout functionality by blacklisting refresh tokens. I have extended the TokenViewBase class to create a custom logout view. But adding permission_classes = (IsAuthenticated,) in...

github.com

 

위의 글에 따르면,

이러한 문제를 해결할 수 있는 방법에는 2가지가 있다.

 

 

1. permission_classes를 삭제하기

사실 refresh token을 전달한다는 것 자체가 이미 해당 사용자가 "로그인"상태임을 나타내는 것이므로, 굳이 permission_classes로 IsAuthenticated를 지정해줄 필요가 없다.

 

Token 이해하기

(1) access token의 유효시간을 매우 짧게 설정함 (token이 탈취당했을 경우를 대비한 것)
(2) access token이 만료될 때마다 로그인(인증)하는 것은 번거로우므로, refresh token을 만들어서 (유효한)refresh token을 던지면 access token을 새로 발급받을 수 있게 함 (-> 즉, 당연히 refresh token의 유효시간은 상대적으로 길다)
(3) 기기에 저장된 refresh token까지 유효시간이 만료되면, 로그인(인증)이 필요하다

즉, 순서가 access token >> refresh token >> 로그인(인증)임.
따라서 refresh token이 유효하다면 로그인 상태인 것이다. 왜냐하면 유효한 refresh token으로 새로운 access token을 바로 발급 받아서 request를 보낼 수 있기 때문이다.


cf. 세션에 비해 token(jwt)가 더 유용한 점
-> 세션은 req마다 db를 오가며 조회해야 하지만, token방식에서는 평상시 req에 담겨 오가는 것은 access token뿐이고 access token이 만료됐을 때만 refresh token이 사용된다.

 

 

2. authentication_classes를 추가로 할당

from dj_rest_auth.jwt_auth import JWTCookieAuthentication
from rest_framework.permissions import IsAuthenticated

class LogoutAPIView(TokenViewBase):
    permission_classes = (IsAuthenticated,)
    authentication_classes = (JWTCookieAuthentication,)

 

하지만 내 가상환경에는 dj_rest_auth.jwt_auth를 추가로 install해야 해서, 나는 1번 방법으로 코드를 수정하고 최종적으로 로그아웃 기능구현을 마무리했다!