DRF

DRF 개발 일기 - 3

Blacklist Token이란?

by HOON


Last updated on May 5, 2024, 5:50 p.m.


random_image

이전 포스트에서는 django의 기본 인증방식인 session을 jwt로 바꾸는 방법을 보여드렸습니다.
이번 포스트에서는 jwt토큰으로 변경하면서 기본적인 보안 위협에 대응하고자, blacklist를 사용하는 방법을 설명드리겠습니다.


토큰 설명


django의 라이브러리 simple jwt가 생성하는 토큰의 상세 종류를 설명드리겠습니다. 총 세가지로 access,refresh,blacklist 로 구성되어있습니다.

  • access_token : 기본적인 토큰으로 refresh와 같이, 사용자 로그인시 생성되며 인증된 상태에서 서버의 특정 리소스에 접근할 수 있게 해주는 토큰입니다. 이 토큰은 일반적으로 짧은 만료 시간을 가지며, 만료되면 더 이상 유효하지 않게 됩니다.
  • refresh_token : refresh 토큰은 access 토큰이 만료되었을 때 새로운 access 토큰을 생성하는 데 사용됩니다. 이 토큰은 일반적으로 access 토큰보다 긴 만료 시간을 가집니다.
  • blacklist_token : 사용자가 로그아웃을 시도하거나 세션을 종료할 때, 클라이언트는 서버에 refresh 토큰을 전송하여 blacklist에 추가할 수 있습니다. 이렇게 하면 해당 refresh 토큰은 더 이상 유효하지 않게 되어, 이 토큰을 사용하여 새로운 access 토큰을 생성할 수 없게 됩니다.

토큰 설명에서 표현한것처럼 blacklist_token을 사용하는 이유는 대충 짐작이 갈겁니다.
이유는 refresh_token의 재사용을 막고자 사용하게됩니다.

JWT토큰은 상태를 유지하지 않는(stateless)특성 때문에, 일단 토큰이 발급되면 만료 시간이 될 때까지 유효합니다.
따라서 로그아웃 등의 상황에서 토큰을 즉시 무효화 해야합니다.


blacklist_token 구현


blacklist_token의 구현은 간단합니다.
settings.py에 기본 작업을 하고, url을 설정하여, 로그아웃시 해당 토큰작업이 되도록 하면 됩니다.

#settigns.py
INSTALLED_APPS = (
    ...
    'rest_framework_simplejwt.token_blacklist',
    ...
)

SIMPLE_JWT = {
    ...
    'BLACKLIST_AFTER_ROTATION':True,
    ...
}
#urls.py
urlpatterns = [
    ...
    path('api/token/blacklist/', TokenBlacklistView.as_view(), name='token_blacklist'),
    ...
]

이후, 실제로 로그아웃이 될 때 코드를 작성해보겠습니다.

<script>
    document.querySelector('.dropdown-item').addEventListener('click', function(event){
        event.preventDefault();

        var refreshToken = localStorage.getItem('refresh_token');

        fetch('/api/token/blacklist/',{
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({refresh: refreshToken})
        })
        .then(response => {
            if (response.ok){
                localStorage.removeItem('refresh_token');
                localStorage.removeItem('access_token');
                window.location.href= '/accounts/logout/';
            } else {
                console.error('Failed to blacklist the token.');
            }
        })
        .catch((error) => {
            console.error('Error:', error);
        });
    });
</script>

dropdown-item은 제가 작성한 로그아웃버튼의 id값입니다.
이 버튼이 클릭 될 때 LocalStorage에서 refresh_token을 가져오고, /api/token/blacklist/ 를 호출하여 blacklist로 전달합니다.
이후, localStorage에 저장된 access, refresh 토큰을 즉시 삭제합니다.

이제, 실제로 refresh 토큰이 blacklist로 이동했는지 확인 해보겠습니다.

우선, 사용자 로그인 시 생성된 토큰입니다.

HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcxNDk4NDc2MSwiaWF0IjoxNzE0ODk4MzYxLCJqdGkiOiI3MDM4YWQwMGU5ZTg0OGE1OGE2ZWY1ODM4ZGMwMzc1YyIsInVzZXJfaWQiOjF9.6F5_Vns55IdySAA4re7kYgNDAqFUa6IOPIB9KynpaDw",
    "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE0OTAxOTYxLCJpYXQiOjE3MTQ4OTgzNjEsImp0aSI6IjBhNDgyNGI5MmVlNjRlMTc4NzBhZTJhN2E3MjcwZTYyIiwidXNlcl9pZCI6MX0.NxQEGiGdhYA-Cu_wPqjzTTec_CuqAULOUaizcHEpVQM"
}

access 토큰과 refresh토큰이 생성 된 것을 볼 수 있습니다.

이제 로그아웃 후, refresh 토큰이 blacklist로 이동되는지 확인해보겠습니다.

이렇게 실제로 BlacklistedToken에 실제로 추가되는걸 볼 수 있습니다.


Leave a Comment:

🤖 AI Chat 🤖