redis 적용하기




Redis 에 대해서는 지난 포스팅에서 간단히 다룬게 있다 (WEB) Redis
복습할 겸 Redis에 대해 다시 알아보고, 뭅스터에 적용해보자.👍

1. redis 란?

  • Remote Dictionary Server의 약어
  • 메모리 기반의 key-value Store
  • Cassandra나 HBase와 같이 NoSQL DBMS로 분류
  • 또한 memcached와 같은 In memory 솔루션으로 분류되기도 함



2. redis 장점

  • 램상(인메모리캐시상)에서 데이터를 정의하여 기존의 하드디스크에서 데이터를 접근하는 것보다 매우 빠른 실행 속도를 보장받을 수 있다.
  • 데이터를 db에 저장하여 서버와 통신한 뒤 그 데이터를 확인하는 것보다 ram에 저장함으로써 시간을 단축시킬 수 있다.



3. redis 단점

  • redis 서버가 초기화되면 redis에 저장된 데이터가 모두 초기화된다.
  • 때문에 중요한 정보, 삭제되면 안되는 데이터는 사용하면 안된다.



4. 뭅스터 적용하기

위의 장담점으로 Redis는 보통 세션 정보를 저장하는데 가장 많이 쓰인다.
뭅스터도 지난 시간에 jwt 를 통해 발급받은 refreshToken은 redis에 저장하여 사용할 것이다.

이제 코드를 살펴보자. 😄

redis 설치 및 세팅

npm install --save redis 해당 명령어를 통해 redis를 설치하자.

config/redis.js

const redis = require('redis');

const redisClient = redis.createClient({ host: '127.0.0.1', port: process.env.REDIS_PORT, db: 0 });

redisClient.on('connect', () => {
  console.log('redis client connected');
});

module.exports = redisClient;

redis 서버에 접근할 client를 만들어주자.

서버 실행 환경에서는 다음과 같이 redis-server와 redis-cli가 실행 가능해야 한다.(이 부분은 생략하겠다.) redis-server



redis에 refreshToken 저장하기

modules/redis.js

const redisClient = require('../config/redis');

const get = idx =>
  new Promise((resolve, reject) => {
    redisClient.get(idx, (err, data) => {
      if (err) reject(err);
      resolve(data);
    });
  });

const set = (idx, token) => redisClient.set(idx, token);

const del = idx => redisClient.del(idx);

module.exports = {
  get,
  set,
  del,
};

redis는 로그인 로직과 인증 미들웨어 로직에서 사용되므로 modules로 별도 분리해놓았다.
이 단계에서는 set만 집중하자.✨

service/admin.js

// login logic ...
 const token = {
      accessToken: await jwt.signAccessToken({ idx: admin.admin_idx, email: admin.email }),
      refreshToken: await jwt.signRefreshToken({ idx: admin.admin_idx, email: admin.email }),
    };

    redis.set(admin.admin_idx, token.refreshToken);

로그인 과정에서, JWT를 사용해 토큰을 발급받고, 해당 토큰을 {adminIdx: refreshToken} 형태로 redis에 저장한다.

adminIdx 가 8인 사용자가 로그인하면, 다음과 같이 redis server에 8-refreshToken이 저장된 것을 확인 할 수 있다. redis-get


redis에서 refreshToken 가져오기

modules/redis.js

...생략

const get = idx =>
  new Promise((resolve, reject) => {
    redisClient.get(idx, (err, data) => {
      if (err) reject(err);
      resolve(data);
    });
  });

...생략

redisClient.get(key)를 통해 redis에 저장된 key값을 가져올 수 있다.
get은 비동기 함수이기 때문에, 콜백함수의 data에 우리가 원하는 refreshToken이 담겨있고,
해당 함수에서 refreshToken을 return 해주기 위해 promise를 사용하였다.

middleware/auth.js

// access 만료 refesh 유효
    const redisToken = await redis.get(refreshToken.idx);

    if (req.cookies.refreshToken !== redisToken) {
      return res.status(CODE.UNAUTHORIZED).json(form.fail(MSG.TOKEN_INVALID));
    }

    const newAccessToken = await jwt.signAccessToken({ idx: refreshToken.idx, email: refreshToken.email });

accessToken이 만료되고, refreshToken은 유효할 때 (JWT 검증상), 서버에서 저장하고 있는 refreshToken 값과도 동일한지 검사한다.
redis 서버에 저장하고 있으므로, modules에서 만든 get 함수를 사용하여 redisToken을 가져오고,
redisToken과 쿠키로 전달받은 refreshToken이 일치하는지 확인한다.

redis에서 refreshToken 삭제하기

로그아웃시에, redis에 저장된 refreshToken을 삭제시켜줘야 한다.

modules/redis.js

const del = idx => redisClient.del(idx);

redisClient.del(key) 를 통해 redis server에서 key값에 해당하는 데이터를 삭제한다.

controller/admin.js

const logout = async (req, res) => {
  redis.del(req.cookies.idx);
  res.clearCookie('accessToken').clearCookie('refreshToken').status(CODE.OK).json(form.success(MSG.LOGOUT_SUCCESS));
};

로그아웃시, redis-server에서 삭제되어 해당 key값으로 조회되지 않는다.
redis-del