[JWT, Redis] JWT, Redis를 활용한 로그인, 로그아웃

코딩은 돈이 된다·2024년 6월 28일
0

JWT

jwt에 대한 이론적인 내용은

JWT,무엇일까

이 글에서 확인해볼 수 있다.

이번엔 이론적인 내용에서 벗어나 실제로 어떻게 사용될 수 있는지 확인해보려고 한다.

Redis

우선 Redis란 key, value 값으로 저장되는 오픈소스 기반의 인메모리 데이터 구조 저장소이다.
쉽게 말해서 캐시 저장소이다.

일반 데이터 베이스와의 차이라고 한다면 데이터 베이스는 물리적으로 값을 써서 데이터를 저장하는 방식인 반면에 Redis의 경우에는 데이터를 주로 메모리에 저장한다. 이는 빠른 데이터 읽기 및 쓰기를 가능하게 하며, 일반적으로 디스크 기반 데이터베이스보다 빠른 속도를 제공한다.

데이터베이스는 계속해서 디스크에 접근해야 하기 때문에 부하가 발생하며 느려질 수 있지만, Redis는 메모리를 거치기 때문에 속도가 빠를 수밖에 없다.

물론 key, value 값으로 저장되기 때문에 쿼리문도 사용할 필요가 없다.

이번 글에서는 자주 사용하는 조합인 JWT와 Redis를 이용하여 실제로 어떻게 서비스가 진행되는지를 다루고자 한다.

로그인/로그아웃

가장 단순한 구조부터 살펴볼 것이다.
우선은 JWT란 토큰을 발급 받아야 인증을 하던 서비스에 접근을 하던 할 수 있다.
그래서 JWT는 로그인 상황에서 발급을 해준다.
JWT 토큰에도 두 가지가 있는데 refresh_token과 access_token이다.

acess_token

이름 그대로 접근하기 위한 토큰인데, 해당 토큰은 유효기간을 짧게 설정한다는 특징이 있다. 인증이 필요한 서비스일 경우에 프론트에서 api 요청을 보낼 때 헤더에 넣어서 보낸다.
서버에서는 해당 엑세스 토큰을 검증하고 처리해준다.

refresh_token

액세스 토큰의 유효기간이 만료되었을 때 사용하는 토큰이다.
클라이언트가 요청한 액세스 토큰이 만료되었다면, 클라이언트는 refresh_token을 사용하여 액세스 토큰을 새로 발급받는다.
유효 기간이 acess_token에 비해 길다는 특징이 있다.


이러한 토큰들의 특징을 이용하여 인증과정을 진행하는데, 왜 굳이 redis를 사용하는 것일까?

해당 이유는 jwt 발급시 특징에 있는데, 서버 측에서는 오직 토큰의 발급만 담당한다. 다시 말해서 발급을 해주기는 하지만, 따로 저장해두지 않는다.

즉, 서버 측에서는 jwt 발급 후에 토큰의 제어권을 완전히 상실한다.

이 부분의 문제를 생각해보자, 결국 받은 토큰을 클라이언트에서 저장하는 식으로 진행될 것이다.

왜 문제일까?

로그아웃 기능을 생각해 보자, 보통 로그아웃을 진행하게 된다면, 클라이언트에서 세션에 저장된 사용자 정보를 지우는 방식으로 진행을 한다.

만약 같은 방식으로 토큰이 세션에 저장되어 있고, 로그아웃 시에 해당 세션에 존재하는 토큰을 지우면 로그아웃이 될 것이다.

그렇게 생각하면 안된다

토큰을 지우더라도, 토큰은 만료되기 전까지 서버에서 인증이 가능하다.
극단적인 예시로, 리프레시 토큰이 탈취되었는데 로그아웃을 진행했다고 해서 토큰 자체가 이용불가 상태가 된 것이 아니기 때문에 만료 기간 전이라면 계속 재발급을 받아서 만료 기간을 계속 초기화 해 사용할 수 있다.

이것을 막을 수 없는 이유는 위에서 설명한 것처럼 서버는 토큰에 대한 제어 기능을 상실한 상태이기 때문이다.

stateless라고 하는데, 서버에서는 올바른 사용자가 보냈는지, 해커가 탈취해서 보냈는지 알 수 없이 토큰만 보고 인증을 해준다.

그래서 ?

여러가지 방식이 있지만, 여기서는 블랙리스트 방식을 사용할 것이다.
블랙리스트 방식이란 말 그대로 출입을 불가하도록 막는 것이다.

어떻게 막을 수 있을까?
로그아웃 시에 리프레시 토큰을 블랙리스트로 처리하면 가능하다.
이렇게 하면 다시 요청이 들어왔을 때에 거절 할 수 있다.

여기서 중요한 점은, 해당 토큰에 대해 알아야 하기 때문에 서버 측에서 해당 토큰 자체를 가지고 있어야 한다는 점이다.

따라서 우리는 Redis를 사용할 수 있다. Redis 내에 리프레시 토큰을 넣어두고, 로그아웃 요청이 왔을 때, Redis 내에 해당 리프레시 토큰을 삭제해준다.
이렇게 하면 리프레시 토큰이 존재하지 않기 때문에 엑세스 토큰의 재발급도 불가능해진다.

여기서 추가로 엑세스 토큰을 블랙리스트 데이터에 추가해주면 조금 더 안전하게 만들 수 있다.
-> 엑세스 토큰이 만료되지 않았을 때 탈취되었더라도 블랙리스트에 등록되어 있기 때문에 인증 불가능

물론 언제까지나 계속 저장해둘 필요가 없기 때문에, 해당 액세스 토큰의 만료 기간동안 존재하도록 설정해두는 것이 좋다.(Redis 자체에서 만료일을 제공하기 때문에 토큰 만료 기간만큼 설정해 두면 자동으로 삭제가 된다)

access_token 재발급 방법

당연히 access token이 만료될 수도 있으니 재발급 방법이 필요하다.

  1. 엑세스 토큰을 헤더에 넣어서 인증이 필요한 서비스에 요청을 보낸다.
  2. 서버에서는 해당 토큰의 valid(ex 만료 기간)를 체크하여 처리한다.
  3. 만약 만료된 토큰이라면, 클라이언트에서 리프레시 토큰을 이용하여 새로운 엑세스 토큰을 요청한다.
  4. 만약 리프레시 토큰이 존재하지 않는다면, 사용자는 다시 로그인을 해야 한다.
  5. 사용자는 새로 발급된 엑세스 토큰을 저장하고, 이후 인증에 사용한다.

이러한 과정을 통해 사용자는 계속해서 인증된 상태를 유지할 수 있다.

마치며

처음에는 django를 사용하며 redis와 jwt를 같이 사용하려고 했다.
이곳 저곳 찾아보면서 공부하려고 했는데, 자료가 잘 나와있지 않더라
알고보니까 simplejwt라는 라이브러리로 블랙리스트 기능을 지원한다.

역시 파이썬이다..

0개의 댓글