엘리스 코딩 1차 프로젝트 회고

Kimhojin_Zeno·2023년 12월 6일
0

프로젝트

목록 보기
2/3

깃허브 링크
https://github.com/C54Kd/sleepyz/blob/main/README.md




기획

엘리스 코딩 SW 6기 1차 프로젝트는 2주 안에 쇼핑몰 페이지를 만드는 것이었다.

2주만에 동작하는 웹 프로젝트를 만들라니. 너무 짧은 것 같았다. 팀원은 6명이고 프론트 3명, 백엔드 3명으로 나뉘었다.

만들어야 하는 기능들은 미리 채점표로 구성되어 있었다. (깃허브 리드미 참조)

https://github.com/C54Kd/sleepyz/blob/main/README.md

로그인, 회원가입 기능, 제품 페이지, 장바구니, 주문 작성, 마이페이지, 관리자 페이지 등.

우리 팀은 침구류 쇼핑몰로 주제를 잡고 기획을 하기로 했다.

채점표가 있었기 때문에 거기에 맞춰 어떻게 구현할지, 어떤 기술 스택을 사용할지를 정했다.

기술 스택

  • JavaScript, HTML, CSS
  • Node.js, Express, mongoDB, multer
  • jwt, bcrypt

이번 프로젝트는 리액트 없이 바닐라 자바스크립트로 웹을 구현했다. node.js와 express로 서버를 만들고 정적 파일을 서빙하는 식으로 구성되었다.

관리자 페이지에서 새로운 상품을 등록하고 삭제하는 기능이 까다로웠는데 multer를 이용하여 이미지를 업로드 할 수 있도록 만들었다.

이미지 업로드와 렌더링 방식에 관한 고민

이미지를 웹 페이지에서 업로드할때, 그것을 처리하는 방식은 크게 두가지가 있다.

첫번째로 클라이언트에서 이미지를 amazon s3 같은 서비스에 업로드하고, 거기서 받은 url을 서버로 보내는 방법,

두번째로 클라이언트에서 이미지를 서버로 보내고, 서버에서 프로세스를 수행하는 방법이 있다. 각 방법의 장점은 첫번째 방법은 서버에 부하를 줄일 수 있고, 두번째 방법은 서버에서 좀더 다양한 기능이나 구현이 가능하다는 점이다. 반대로 단점은 첫번째 방법은 프론트 코드에 업로드 되는 DB에 관한 정보가 노출된다는 점, 두번째 방법은 서버가 이미지를 처리함으로써 부하가 걸린다는 점이다.

처음 시도는 첫번째 방법으로 시도했다. 클라이언트에서 firebase에 이미지를 보내고, url을 받아서 url만 서버로 보내는 방식으로.

그러나 이렇게 하니 프론트 코드에서 firebase의 스토리지 계정 정보 등 환경변수가 노출되었다. 리액트를 사용했다면 dotenv로 숨길 수 있을텐데, 지금 프로젝트에서는 프론트는 express가 서빙해주는 정적 파일 그 자체이다. 따로 build 단계가 없이 모든 코드가 노출된다. 다른 방법이 있었겠지만 당장 생각이 나지 않았다.

코치님께 질문하니 두번째 방법으로 바꾸는 게 낫다고 하셨다. 따라서 두번째 방법으로 전환했다.

클라이언트에서 이미지를 서버로 보내고, 서버에서 multer라는 라이브러리로 받아서 firebase에 저장한다. 그 후 url을 프론트로 보내 업로드된 이미지가 확인된다.

access token과 refresh token

로그인을 할때 매번 비밀번호를 입력할 필요가 없이 브라우저의 쿠키에 액세스 토큰이 저장되어 로그인되게 하는 기능을 구현하였다.

최초 로그인시 서버에서 액세스 토큰을 발급해주고 클라이언트로 보내준다. 그러면 브라우저는 토큰을 로컬 스토리지나 쿠키에 저장한다. 그 이후 로그인부터는 이 토큰을 서버로 보내고, 서버가 검증한 다음 맞으면 로그인시켜주는 것이다.

그러나 액세스 토큰은 탈취 위험성 때문에 유효기간을 짧게 가져간다. 리프레시 토큰은 액세스 토큰이 만료 시간이 지난 후에 액세스 토큰을 갱신하기 위해 사용하는 토큰이다. 프로젝트 목표에 리프레시 토큰 구현까지는 있지 않았지만 공부해보며 구현해보고 싶은 욕심에 리프레시 토큰까지 구현하였다.

JWT라는 라이브러리를 사용하며 토큰을 만들 수 있다. JWT는 Json web token의 약자로 암호화되어 header, payload, signature로 이루어진다.

refresh token의 작동방식

리프레시 토큰은 액세스 토큰을 갱신해준다는 기능은 동일하지만 리프레시 토큰을 어디에 저장할 것인가 하는 것에 관해서는 여러 방법이 존재한다.

리프레시 토큰을 아예 DB에 저장하는 법, 클라이언트에 주는 경우 로컬스토리지에 주는 법, 쿠키에 http only 옵션으로 주는 법 등이 있다. 로컬 스토리지에 저장하는 것은 쿠키에 저장하는 것보다도 보안이 떨어진다. 매우 쉽게 탈취 될 수 있다. DB에 저장하는 법은 웹에 많은 예제가 나와 있지만 그렇게 하면 안된다는 반대 정보도 많았다. 리프레시 토큰을 쓰는 전략은 매우 다양한데 아직까지는 통일된 하나의 대세라고 할만한 방법은 없는 것같다.

개인적으로는 리프레시 토큰을 클라이언트에게 주지 않고, DB에만 저장했다가 액세스 토큰이 만료되었다면 DB에서 리프레시 토큰을 가져와서, 그것을 검증해서 액세스 토큰을 만드는 방식을 취한다면, 굳이 리프레시 토큰을 사용하는 의미가 없지 않나? 하는 생각이 들었다. 이 방식이 그냥 액세스 토큰의 만료 기한을 늘리는 것과 무슨 차이가 있을까? 그렇게 하면 이건 리프레시 토큰이 아니라 액세스 토큰을 만들기 위한 키에 불과하지 않은가?

토큰은 클라이언트가 서버에게 제시해서 권한을 있는지 없는지를 판별하는 것인데 이 본질이 뒤바뀌는 것 같았다. 물론 DB에 저장해서 얻는 이점도 있겠지만 짧은 프로젝트 기간 중 내가 파악한 지점은 이것이다.

나는 쿠키에 http only 옵션을 줘서 저장하는 방식으로 리프레시 토큰을 구현했다.

액세스 토큰의 만료기한은 하루, 리프레시 토큰의 만료기한은 1주이다.

배포 후 회고

2주라는 짧은 시간에 처음 손발을 맞춰보는 팀원들과 작동하는 쇼핑몰을 만들 수 있을까 하는 걱정이 많았다. 시간이 매우 부족해서 사실 발표날 아침까지도 밤을 새며 디버깅을 했다.

그러나 무사히 배포하고 꼼꼼하게 체크리스트를 만들어 기능을 구현하고 디버깅을 했기 때문에 결과적으로 대부분의 목표 기능을 성공적으로 구현했다.

나는 백엔드 팀이었는데 express로 서버를 빌드단계부터 시작해서 끝까지 만들어본 것은 처음이었다. 매우 유익한 경험이었다. 또 혼자 하기보다는 디스코드 음성채팅방에 백엔드 팀원들과 같이 화면공유를 하면서 페어 프로그래밍으로 많이 진행하였는데, 이 방법이 굉장히 도움이 된다는 것을 깨달았다. 막히는 지점에서 두명이 고민하니 두배로 빠르고, 내가 느릴때도 다른 사람의 속도에 따라가기 위해 노력하기 때문에 혼자서 처지는 것을 막을 수 있다.

이런 협업의 과정에서 커뮤니케이션이 무엇보다 중요하다는 것도 깨달았다. 결국 사람이 만드는 것이기 때문에 불필요하거나 잘못 이해되는 커뮤니케이션이 매우 큰 로스를 가져왔다. 팀 간의 커뮤니케이션은 더더욱 그렇다. 백엔드 팀은 순조롭게 진행이 되었지만 프론트 팀은 웹팩 등의 이슈로 상당부분 지체되었고 결국 관리자 페이지는 백엔드 팀이 프론트까지도 구현했다. 막판가지 포기하지 않고 해냈다는 점에서 뿌듯했다.

짧은 시간에 집중적으로 무언가를 만드는 방법이 프로그래밍을 배우는데 매우 효과적이라는 것도 알게 되었다.

결과는 놀랍게도 최우수상을 받았다. 프로젝트 마지막날까지 포기하지 않고 관리자 페이지를 끝까지 모두 다 구현하고, 핫픽스로 디버깅을 한 노력이 결실을 본 것 같아서 기뻤다. 정해진 시간 내에 정해진 기능을 빠짐 없이 구현하는 것, 데드라인을 지키는 것이 중요하고 그러기 위해 빈틈없는 계획과 팀웍이 중요하다는 사실을 다시 한번 깨달았다.

profile
Developer

0개의 댓글