본문 바로가기
프로젝트 개발 기록/[개발] node.js | nest, express

[TypeScript+Express] Redis로 Refresh Token 관리

by HelloJudy 2022. 6. 21.

0. 개요

 

이전 프로젝트에서는 MongoDB를 사용하면서 Refresh Token을 DB에 저장했다.

이번에는 Redis를 연결하여 구현을 해보자.

 

지난 포스팅에서 JWT에 대한 개념을 올렸기 때문에 이번에는 Redis에 초점을 맞춰서 작성하도록 하겠다.

 

👉 [Node.js+Express] Refresh Token 구현

 

 

 

1. 사용 이유

 

[ 왜 Refresh Token을 저장해야할까 ] 

 

Access Token은 서버에 따로 저장해 둘 필요가 없지만, Refresh Token의 경우 서버의 stroage에 따로 저장해서 이후 검증에 활용해야 한다.

 

검증을 위해 서버는 Refresh Token을 별도로 저장하고 있어야 하며,

Refresh Token을 이용한다는 것은 추가적인 I/O 작업이 필요하다는 의미이며, 이는 I/O 작업이 필요없는 빠른 인증 처리를 장점으로 내세우는 JWT의 스펙에 포함되지 않는 부가적인 기술이다.

 

Refresh Token은 탈취되어서는 곤란하므로 클라이언트는 보안이 유지되는 공간에 이를 저장해두어야 한다.

Refresh Token은 서버에서 따로 저장을 하고 있기 때문에 강제로 토큰을 만료시키는 것이 가능하다.

 

즉, 정리하면 JWT의 기본 장점을 보았을 때 서버에 저장할 필요가 없다.

하지만, 토큰이 탈취 당했을 경우 강제로 토큰을 만료 시키는 등 전략을 세우기 위해서 서버에서 리프레시 토큰을 저장하도록 구현하였다.

 

 

[ 왜 Redis에 저장할까 ]

 

Remote Dictionary Server (DB) 이며, In-memory Data structure Store 로, 메모리 상에 데이터를 저장한다.

다양한 자료 구조를 저장하지만, 기본적으로 모든 데이터는 Key-Value 쌍을 이루기 때문에 NoSQL DB 로 활용된다.

 

즉, 휘발성으로 저장하지만 매우 빠른 엑세스 속도를 가진다.

 

그래서 이유를 두 가지로 생각해볼 수 있다.

 

1) 빠른 엑세스 속도

 

Refresh Token을 이용한다는 것은 추가적인 I/O 작업이 필요하다는 의미이다. 

이때 디스크에서 읽어오는 것이 아니라 메모리에서 바로 읽을 수 있기 때문에 빠르게 처리할 수 있다.

그래서 로그인 시 병목 현상을 줄일 수 있다.

 

2) 토큰 만료

 

Refresh Token은 만료시간이 있다. Refresh Token을 일반적인 DB에 저장하면, 스케줄러로 주기적으로 만료된 토큰을 제거해야한다.

하지만, Redis는 값을 저장할 때 데이터 유효기간(time to live)을 지정할 수 있다.

 

2. 구현

 

1) 일단 기본적으로 Redis를 설치해야한다.

 

2) node와 연결하기

 

$ yarn add redis

 

3) DB 연결

 

import * as redis from "redis";
import dotenv from "dotenv";
dotenv.config();

// const port = process.env.REDIS_PORT || 6379;
// const redisHost = process.env.REDIS_HOST || "127.0.0.1";
const redisClient = redis.createClient();

redisClient.connect();

redisClient.on("ready", () => {
  console.log("redis is ready");
});

redisClient.on("error", (error) => {
  console.error(error);
});

export default redisClient;

 

 

4) 로그인 시 Redis에 저장

 

    // 로그인 성공 -> access token, refresh token 발급 + redis 저장
    const accessToken = makeToken({ userId: user.pk_user_id });
    const refreshToken = makeRefreshToken();
    redisClient.set(user.pk_user_id, refreshToken);

 

 

5) 로그아웃 시 Refresh Token 삭제

 

const getRefreshToken = await redisClient.get(pk_user_id);
    if (!getRefreshToken) {
      throw new HttpException(401, "로그인 내역이 없습니다. 다시 한 번 확인해주세요.");
    }
    redisClient.del(pk_user_id);

 


📌 Reference

반응형

댓글