본문 바로가기
Back-end/기초부터 따라하는 nest.js

#9. 기초부터 따라하는 Nest.js : 로그인의 원리와 Guard(1) - 개념편

by hsloth 2023. 4. 17.

 

해당 포스팅은 nest.js 9.0.0 버전, typeorm 0.3.x 버전을 기준으로 작성되었습니다.
모든 글은 작성자의 주관이 100% 담겨있기 때문에 부정확할 수 있습니다.

 

#pre. 터미널을 켜고 프로젝트 폴더로 이동

https://suloth.tistory.com/44

 

#0-1. 기초부터 따라하는 nest.js : 터미널 키는 법 + 터미널에서 작업 폴더 이동

윈도우 윈도우는 윈도우+R 버튼을 누른 후, cmd 를 입력하여 터미널을 킵니다. 혹은 윈도우 버튼을 눌러서 검색창에 cmd를 검색하면 터미널이 나올텐데 그걸 실행시켜주시면 됩니다. Mac OS Mac의 경

suloth.tistory.com

 
위의 링크의 내용을 참고하여 study 폴더로 이동해줍니다.
그리고 code . 명령어를 통해 vscode를 열어줍니다.


지난번 포스팅에서 회원가입 로직을 만들어봤습니다.

 

https://suloth.tistory.com/75

 

#8. 기초부터 따라하는 Nest.js : TypeORM을 이용한 간단한 API작성

해당 포스팅은 nest.js 9.0.0 버전, typeorm 0.3.x 버전을 기준으로 작성되었습니다. 모든 글은 작성자의 주관이 100% 담겨있기 때문에 부정확할 수 있습니다. #pre. 터미널을 켜고 프로젝트 폴더로 이동 ht

suloth.tistory.com

이전 포스팅에서는 회원가입을 만들었으니, 로그인 로직을 만들 계획입니다.

하지만 그 전에, 간단히 로그인과 Guard에 대한개념을 짚어보겠습니다.

참고로, Jwt를 사용한 로그인을 구현할 계획입니다.


로그인 방식


기본적인 로그인 방식은 두 가지가 있습니다.

1. JWT

2. Session

 

JWT

Json Web Token의 줄임말으로, Json형식의 Token을 발급받아서 신분증처럼 사용하는 것입니다.

쉽게 말해서 신분증, 주민등록증이라고 생각하시면 됩니다.

하지만, 주민등록증에는 민감한 정보가 모두 담겨있는 만큼. 잃어버리면 자신의 중요한 정보를 함께 잃어버리는 것이므로 보안에 있어서 상대적으로 취약합니다.

 

Session

클라이언트의 상태정보를 서버에 저장하여 다루는 기술을 말합니다. (클라이언트란 고객이라는 뜻으로 브라우저 혹은 프론트엔드 쪽을 의미합니다. 서버란 nest.js로 실행시키는 백엔드 서버를 말합니다)

세션은 브라우저의 쿠키라는 곳에 sessionID를 저장하여 통행증처럼 사용합니다. 그리고 서버는 sessionID(통행증)를 확인하여 해당 고객이 통행허가목록(세션)에 등록이 되어있는지 확인합니다.

JWT와 달리 sessionID에는 민감한 정보들이 저장되어 있지 않아, 탈취당해도 비교적 안전합니다. (저도 아직 자세하게는 모르겠어서 솔직히 보안은 거기서 거기인것 같습니다. 비교적 안전하다고 하는 이유는, sessionID를 탈취당해도 서버에서 해당 sessionID를 탈취당한 사실을 알았다면, 해당 sessionID를 사용불가능하게 만들어 세션(중요정보가 담긴 통행허가목록)으로의 접근을 막을 수 있기 때문입니다. 물론, 탈취당한 사실을 깨닫기 전에 정보를 가져가버리면 말짱꽝입니다. JWT는 JWT만 탈취당하면 모든 정보들이 거기 있으니 비교적 취약하다고 하는 것입니다)

그리고 중요한 정보들은 서버의 세션(통행허가목록)에 저장이 되어 비교적 안전합니다.

대신, 클라이언트(사용자)가 요청을 보낼 때마다 서버에서 확인을 하는 작업이 필요하기 때문에 서버에 부하가 걸릴 수 있습니다.

 

결론

JWT는 주민등록증(신분증)이다. 탈취당하면 민감한 정보가 함께 탈취당한다.

Session은 통행허가목록이다. sessionID는 통행증이다. sessionID는 탈취당해도 크게 문제 없지만, 탈취당한 sessionID로 세션(통행허가목록)에서 민감한 정보를 빼갈 수 있기 때문에 조심해야한다.

 


로그인 시 일어나는 일


1. 로그인을 한다.

JWT의 경우,

사용자가 아이디와 비밀번호를 입력해서 서버로 보내면 서버에서 JWT를 발급해서 사용자의 브라우저로 넘겨준다(저장장소는 프론트엔드 개발자가 정합니다. 백엔드 개발자가 알 필요는 지금은 딱히 없습니다)

 

Session의 경우,

사용자가 아이디와 비밀번호를 입력해서 서버로 보내면 서버에서 SessionID를 발급해서 Session(통행허가목록)에 추가한다. 그리고 해당 SessionID를 사용자의 브라우저로 넘겨준다(저장장소는 보통 쿠키입니다)

 

2. 사용자가 로그인 권한이 필요한 페이지를 요청한다 (ex. 마이페이지)

JWT의 경우,

HTTP 메소드를 서버로 날릴 때, 사용자의 브라우저에서 JWT를 함께 보내서 (Authorization헤더에 Bearer <JWT> 형태로 함께 보낸다. 지금 자세히 알 필요는 없다) 신분증을 보여주고, 서버에서는 해당 신분증을 보고 마이페이지로의 접근을 허락해준다.

 

Session의 경우,

HTTP 메소드를 서버로 날릴 때, 사용자의 브라우저의 cookie에서 sessionID를 함께 보내서 (어.. 이건 정확하진 않은데 아마 Cookie 헤더에 함께 넣어서 보낼겁니다) 통행증을 보여주고, 서버에서는 해당 통행증을 보고 세션(통행허가목록)에 있는지 확인한 후 마이페이지로의 접근을 허락해준다.

 


Guard


가드, 말그대로 막아주는 녀석입니다. 경비원입니다. 사용자가 유효한지 파악하여 해당 API로의 접근을 허용하거나 막습니다.

 

Nest.js의 기본 라이프 싸이클은 다음과 같습니다.

음.. 어딘가에서 퍼온건데, 문제시 삭제하겠습니다.

HTTP Request가 들어오면(클라이언트에서 요청이 들어오면) Guard를 제일 먼저 거칩니다. 이 때, HTTP 요청과 함께 신분증이나 통행증이 있는지 검사를 하고, 없으면 다음 진행을 막습니다. (status 403 코드와 함께 권한 에러를 응답합니다)

 

그래서 우리가 Nest.js에서 로그인을 위해 작성해야 할 코드는 Guard와 관련된 코드입니다.


추가로 알아두면 좋은 정보


여기서부터는 지금 굳이 알 필요가 없는 정보입니다. 빠르게 배우고 싶으신 분은 이 부분은 넘어가도 좋습니다.

 

서버를 여러 대 사용하는 경우

보통 서버를 하나만 사용하면 과부하가 걸리는 경우가 많아 여러 대의 서버를 사용하는 경우가 많습니다.

 

서버가 여러 대일 경우, JWT를 사용하면 무리없이 로그인을 처리할 수 있습니다. JWT 자체가 신분증이기 때문에 어느 서버에 JWT를 제출해도 모든 서버가 해당 유저에 대해 알고 있기 때문입니다.

 

하지만, Session의 경우는 다릅니다. Session은 각 서버마다 생성이 되고 각 서버에서 발급을 해주는 것이기 때문에, 서버1 에서 로그인을 해서 sessionID(통행증)을 발급 받으면 해당 sessionID(통행증)에 대한 세션(통행허가목록)은 서버1에만 등록되어있지, 서버2와 서버3에는 등록되어있지 않습니다. 따라서, 서버1에서 로그인을 하고 서버2에다가 마이페이지를 보여달라고 요청하면, 서버2는 해당 sessionID가 세션(통행허가목록)에 등록되어있지 않기 때문에 로그인이 되어있지 않다고 알립니다.

 

서버를 여러 대 사용하는 경우의 Session의 문제를 해결하기 위해

Sticky Session, Session Clustering 등의 방법을 사용합니다. 이 부분은 각자 구글링해서 찾아봅시다. 그리고 요즘에는 JWT+Session을 같이 사용하는 방법도 존재한다고 합니다. 관심이 있으면 찾아보시길 바랍니다.