로그인 원리
로그인을 통해 사용자의 인증 정보를 저장하고, 그 후 인증된 사용자가 어떤 식으로 웹사이트를 이용하는지 간단하게 알아보자.
- 사용자가 웹사이트에서 아이디 및 비밀번호를 이용해서 로그인을 시도하면(아래 그림에서 1번)
- 사용자가 만일 정확한 아이디와 비밀번호를 입력했다면, 서버는 인증(Authentication)에 성공했다고 판단할 것이다.
- 다음번에 인증을 필요로 하는 작업(e.g. 그림에서와 같이, 장바구니에 물품 추가)을 요청할 경우에 한번 더 로그인 과정을 거쳐야 할까?
- 아니 다.
- 서버가 "해당 유저는 인증에 성공했음"을 알고 있다면, 유저가 매번 로그인할 필요가 없다.
인증에 따라 리소스의 접근 권한(Authorization)이 달라진다.
이때 클라이언트와 서버에 각각 필요한 것은 다음과 같다.
- 클라이언트 : 인증 성공을 증명할 수단을 갖고 있어야 한다.
- 사용자가 인증에 성공한 상태는 세션이라고 한다.
- 서버 : 사용자가 인증에 성공했음을 알고 있어야 한다.
- 서버는 사용자가 인증에 성공하면 로그인 상태를 유지하기 위해 해당 사용자의 정보를 담은 세션 객체를 생성한다.
- 그 뒤, 일종의 저장소에 세션을 저장한다. (그림에서 2번)
- 주로 in-memory(자바스크립트 객체를 생각하면 된다),
- 또는 세션 스토어(redis 등과 같은 트랜잭션이 빠른 DB)에 저장한다.
- 세션이 만들어지면, 각 세션을 구분할 수 있는 세션 아이디도 만들어지는데 (그림에서 3번),
- 보통 클라이언트에 세션 성공을 증명할 수단으로써 세션 아이디를 전달한다. (그림에서 4번)
- 서버는 사용자의 세션을 유지하기 위해 쿠키에 서버에서 발급한 세션 아이디를 저장하는데,
- 이에 접근할 수 있는 id를 암호화하여 쿠키로 사용자에게 전달한다.
이때 웹사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용한다.
쿠키에는 서버에서 발급한 세션 아이디를 저장한다.
- 쿠키를 통해 유효한 세션 아이디가 서버에 전달되고, (그림에서 5번)
- 세션 스토어에 해당 세션이 존재한다면 (그림에서 6번)
- 서버는 해당 요청에 접근 가능하다고 판단한다. (그림에서 7,8번)
하지만 쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려준다.
로그아웃 원리
그렇다면, 로그아웃은 어떻게 구현해야 할까?
- 세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있다.
- 그리고 서버는 그저 세션 아이디로만 인증 여부를 판단한다.
[주의]
쿠키는 세션 아이디, 즉 인증 성공에 대한 증명을 갖고 있으므로, 탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단한다. 이것이, 우리가 공공 PC에서 로그아웃해야 하는 이유이다.
그러므로 로그아웃은 다음 두 가지 작업을 해야 한다.
- 서버: 세션 정보를 삭제해야 한다.
- 클라이언트: 쿠키를 변경하거나 삭제해야 한다.
클라이언트에서 세션 정보를 없애기 위해서는 res.cookie로 쿠키의 값을 무효한 값으로 변경하거나, res.clearCookie로 쿠키를 삭제해 버리면 된다.
express-session
Node.js에는 이런 세션을 대신 관리해 주는 express-session이라는 모듈이 존재한다.
- express-session은 세션을 위한 미들웨어로, express 서버에서 쉽게 세션을 위한 공간을 다룰 수 있도록 만들어준다.
- 아래 설명을 참고하여 모듈의 역할 및 사용법을 알아보자.
- express-session를 사용해 아래와 같이 세션의 옵션을 지정할 수 있다.
const express = require('express');
const session = require('express-session');
const app = express();
app.use(
session({
secret: '@codestates',
resave: false,
saveUninitialized: true,
cookie: {
domain: 'localhost',
path: '/',
maxAge: 24 * 6 * 60 * 10000,
sameSite: 'none',
httpOnly: false,
secure: true,
},
})
);
언뜻 보면 쿠키 옵션과 비슷해 보인다.
- 하지만 세션의 경우 secret 옵션의 비밀키를 이용해 암호화해 세션 id라는 것을 생성한다. 그리고 이것을 클라이언트에게 쿠키로 전송한다.
- 쿠키로 전송된 세션 id는 이에 종속되는 고유한 세션 객체를 가지며 이는 서버에 저장된다. 이때 세션 객체는 유저별로 독립적으로 생성된 객체이므로 유저별로 각각 다른 데이터를 저장할 수 있다.
- 따라서 클라이언트에 유저의 개인정보를 담지 않고도 서버가 클라이언트의 세션 id를 이용해 유저의 인증여부를 판단할 수 있다.
- 세션 객체는 req.session으로 접근할 수 있으며 앞서 말했듯 이를 통해 세션에 임의의 데이터를 저장하거나 불러올 수 있다.
이 세션 객체에 값을 담거나, 값을 불러오는 법, 세션을 파괴하는 법은 다음 문서를 참고 : GitHub: express-session
쿠키와 세션 차이점
+ 세션은 서버 혹은 유저가 종합적인 로그인 상태를 관리할 수 있다.
- 예) 데스크톱 접속, 휴대폰 접속, 카카오톡 로그인 등 다양한 기기 혹은 환경에서 로그인 되어 있는 상태를 관리할 수 있음.
- 특정 기기에서의 계정 사용에 문제가 있는 경우 서버나 유저가 해당 계정을 삭제할 수 있다.
세션기반 인증 방식의 한계
서버가 유저의 상태(State)를 관리하므로 다수의 서버를 사용할 경우, 서버간 세션 데이터 공유가 필요하다.
- 공통의 세션 스토어를 구축하거나
- 세션 클러스트링을 통해 분산된 서버 간의 세션 데이터를 동기화하거나
- 세션 클러스터링(Session Clustering)은 여러 대의 웹 서버가 하나의 세션 클러스터로 구성되어 클러스터 내의 모든 서버가 세션 정보를 공유하는 기술이다.
- 이를 통해 분산된 서버 간에도 세션 데이터를 공유할 수 있다.
- 세션 클러스터링을 구현하면 하나의 서버가 다운되어도 다른 서버에서 해당 세션에 대한 처리를 계속할 수 있다.
- 세션 어피니티를 통해 하나의 서버로만 요청을 보내도록 구현해야 함.
- 세션 어피니티(Session Affinity) 또는 세션 지속성(Session Persistence)은 분산된 서버 환경에서 로드 밸런싱을 수행할 때, 한 클라이언트의 모든 요청이 항상 같은 서버로 전달되도록 하는 방법이다.
- 이를 통해 같은 세션 정보를 유지할 수 있다.
- 세션 어피니티를 구현하면 클라이언트가 처음 요청한 서버에서 세션을 유지하므로, 해당 서버가 다운되지 않는 이상 항상 같은 세션 정보를 사용할 수 있다.
728x90
'FE > Server' 카테고리의 다른 글
OAuth (0) | 2023.05.04 |
---|---|
해싱(Hashing)과 토큰(Token) 인증 방식 (0) | 2023.05.03 |
쿠키(Cookie)의 개념과 작동원리 (0) | 2023.05.02 |
mkcert를 이용한 로컬에서 HTTPS 서버 만들기 (0) | 2023.04.28 |
[Network] Airline 서버 구현 (2) : 서버 개발하기 (0) | 2023.04.09 |