청소 플랫폼 만들기 (22)

김민준·2023년 9월 9일
0

청소 플랫폼 만들기 (22)

공부하며 느낀 점
참조한 페이지

청소 플랫폼 만들기 (22)

http-only 외에도...

secure : HTTPS에서만 쿠키를 사용할 수 있게 해주는 것이다.
HTTP 환경으로 개발하고 있으므로 적용 할 수 없다.
방법은 간단해서 아래와 같다고한다.

→ document.cookie = "promo_shown=1; Max-Age=2600000; Secure""promo_shown=1; Max-Age=2600000; Secure"

SameSite : CrossSite로 쿠키가 전송되지 않도록 하는 옵션이다. 즉, 같은 프로토콜, 호스트, 포트가 아니라면 쿠키를 전송하지 않는 것이다.

  • None : 제한 없음
  • Lax : 서드 파트 쿠키(타사쿠키)는 전송되지 않지만 예외 설정이 가능하다.
  • Strict : 퍼스트 파티 쿠키(자사쿠키)만 전송된다.

퍼스트 파티는 사용자가 직접 상호작용하고 있는 웹사이트, 서드 파티는 상관 없는 사이트이다.

결국 쿠키 세팅은 아래와 같이 바뀌었다.

res.cookie('Authorization', token.acessToken, { httpOnly: true });
 ↓  ↓  ↓  ↓  ↓  ↓  ↓ 
 res.cookie('Authorization', token.acessToken, {
   httpOnly: true,
   secure: true,
   sameSite: 'strict',
 });

레디스 Redis

Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 NoSQL, DBMS이다. 모든 데이터를 메모리에 저장하고 조회하는 인메모리 데이터베이스이다.

사용하는 이유 : DB는 안정적이지만 사용자가 늘어나면 과부하가 일어날 수 있다. 그것을 막기 위해 캐시 서버를 사용한다. Redis는 그 캐시 서버 중 하나이다. 하지만 데이터의 영속성을 보장하기 때문에 서버가 내려가더라도 디스크에서 데이터를 읽어서 메모리에 로딩을 한다. 또한 Sorted-Set 이라는 자료구조를 사용하면 빠르고 간단하게 데이터를 정렬할 수 있다.

레디스의 특징

  • key-value 구조 : 쿼리가 불필요하다.
  • 캐시 방식이라서 데이터 처리 속도가 빠르다.
  • String, Lists, Sets, Sorted Sets, Hashes 자료 구조를 지원한다.
  • 싱글 스레드 Single Threaded : 하번에 하나의 명령 처리 가능.
    (get, set의 경우 초당 10만개 이상 처리)

레디스 적용시 주의점

  • 인메모리 데이터 저장소이기 때문에, 서버 장애시 데이터 유실이 발생할 수 있다. 대책이 필요하다.
  • 메모리 관리를 잘 해야한다.
  • 싱글스레이드이기 때문에 오래걸리는 요청/명령은 피해야한다.

리프레시 토큰

이제 진짜로 리프레시 토큰을 만들어보자 어제의 내용을 보자면

JWT가 만료 됐을 때의 err.name 은 TokenExpiredError임을 알 수 있다.

} catch (error) {
  if (error.name === 'TokenExpiredError') {
    //블라블라
  } else {
    console.log(error);
    res.status(400).json({ errorMessage: '잘못된 접근입니다.' });
  }
}

캐치문에 넣어보자.

잘 나온다...

중간 과정은 기록하지 못했지만 많은 고통(?) 끝에 엑세스 토큰을 검증하는 과정을 따로 함수로 만들었다.

exports.decode = (req, token, cookie_secret, res) => {
  try {
    const decode = jwt.verify(token, cookie_secret);
    return decode;
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      console.log('엑세스 토큰이 만료되었습니다.');

      const refreshToken = req.cookies.refresh;
      console.log(refreshToken);
      const reToken = refreshToken.split(' ')[1];

      try {
        jwt.verify(reToken, cookie_secret);
        const decode = jwt.decode(token, cookie_secret);
        console.log('리프레시 토큰 검증 성공');

        let accessToken = jwt.sign(
          {
            email: decode.email,
            userId: decode.userId,
            permission: decode.permission,
          },
          process.env.COOKIE_SECRET,
          {
            expiresIn: process.env.JWT_EXPIRE_TIME,
          }
        );

        console.log(accessToken);

        permissionCache.setPermissionCache(decode.userId);

        function bearer(token) {
          const TYPE = 'Bearer';
          token = TYPE + ' ' + token;
          return token;
        }

        accessToken = bearer(accessToken);

        res.cookie('Authorization', accessToken, { httpOnly: true, sameSite: 'strict' });

        return accessToken;
      } catch (error) {
        console.error('리프레시 토111큰 검증 오류:', error);
      }
    } else {
      console.error('토큰 검증 오류:', err);
    }
  }
};

만약 엑세스 토큰만 만료 되었다면 자동으로 엑세스 토큰을 새로 만들고 최신화한다.

만약 엑세스 토큰 뿐 아니라 리프레시 토큰 마저도 만료되었다면 위와같은 에러 페이지가 뜬다.

현재는 개발중이니 이렇게 띄우고, 개발이 끝나면 해커가 사이트 구조를 알 수 없도록 에러 메시지를 두루뭉술하고 똑같이 띄워야겠다.

내일 할 일

  • 엑세스 토큰만 + 엑세스 토큰도 만료 된 경우를 상정해서 코드를 짜기
  • 최대한 모듈화해서 유지보수 용이하게 하기

사소한 버그들

  1. 사장 외의 권한으로 로그인 시 페이지가 제대로 표시 되지 않음
    적절한 예외처리로 제대로 표시 되게 함

  2. 메일등의 형식을 제대로 입력하지 않아도 회원가입이 가능하다.
    → 내일 팀원들한테 이야기 할 예정, 만약 한다고 치더라도 구현한뒤 주석처리해서 테스트 편의성을 유지해도 좋을 것 같다.

공부하며 느낀 점

이제 슬슬 감이 잡혀간다. 특히, 함수를 모듈화해서 돌려쓰는건 할수록 좋은 기술인것같다.

참조한 페이지

SameSite 쿠키 설명
CORS와 쿠키(Same-Site, Secure, httpOnly)
SameSite 쿠키 설명
쿠키 그리고 서드파티 쿠키란 무엇일까 (Cookie)

Redis란? 레디스의 기본적인 개념 (인메모리 데이터 구조 저장소)
[DB] Redis란 무엇일까? 간단하게 알아보기!

profile
node 개발자

0개의 댓글

관련 채용 정보