Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

나만의 개발 로그 | 고민 로그

Redis를 활용한 AccessToken BlackList 저장(로그아웃 기능) 본문

웹 개발

Redis를 활용한 AccessToken BlackList 저장(로그아웃 기능)

ultramancode 2023. 4. 13. 00:36

1. 왜 블랙리스트 기반 로그아웃이 필요한가?

JWT는 Stateless 구조이기 때문에 한 번 발급된 토큰은 만료되기 전까지 서버가 강제로 폐기할 수 없다.
따라서 로그아웃 시 다음과 같은 문제가 발생한다:

  • 단순히 프론트에서 로컬스토리지/쿠키를 지우는 것은 보안상 완전한 로그아웃이 아님.
  • 악의적인 사용자가 토큰을 복사해 두었다면 재사용 가능.
  • 이를 막기 위해선 서버에서 강제로 토큰을 무효화시킬 방법이 필요함 → 블랙리스트 방식 사용.

따라서 만약 프론트엔드에서 로컬스토리지를 비우는 방식으로 처리하는 것이 아니라 

백엔드 단에서 로그아웃 기능을 구현한다면 어떻게 될까 싶어서 블랙리스트 기반으로 구현을 했다.

2. 왜 Redis를 AccessToken 저장소로 사용했나?

  • Redis는 인메모리 기반 저장소이기 때문에 I/O 부하가 적고 조회 속도가 빠름.
  • 블랙리스트 조회는 매 요청마다 Filter에서 수행되므로, 성능이 중요함.
  • 일반 RDBMS에 저장하면 I/O 병목 발생 가능성 있음.
  • Filter는 모든 요청의 초입에 실행되므로, 이 단계에서의 처리는 반드시 경량화되어야 한다고 판단했음.

 

key값으로 token을 넣었다.

이후 기존 Filter단계에서 AccessToken이 블랙리스트에 저장돼있는지 여부를 한번 더 체크하게 만들었다.
또한 TTL을 설정하여 Redis가 자동으로 만료된 블랙리스트 항목을 삭제하게 했으므로, 별도 GC(정리)가 필요 없게 했다.

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
    FilterChain filterChain) throws ServletException, IOException {
  try {
    String accessToken = jwtUtil.resolveAccessToken(request);
    if (accessToken != null) {
      Object blackList = redisDao.getBlackList(accessToken);
      if (blackList != null) {
        if (blackList.equals("logout")) {
          throw new IllegalArgumentException("로그아웃된 토큰입니다.");
        }

3. Refresh Token도 해당 사항 고려

  • 로그아웃 시에는 RefreshToken도 폐기해야 함.
  • Redis에 저장된 RT도 함께 제거 → 재발급 방지.
Comments