로그인 인증 방식 (세션-쿠키 인증) 원리, 동작 흐름 (ft. bcryptjs)


1. 세션과 쿠키란?


세션과 쿠키 둘은 클라이언트와 서버 간의 상태 정보를 저장하고 교환하는 데 사용된다.
세션과 쿠키가 뭔지 자세히 알아보자.

세션(Session)

세션은 서버 측에서 사용자 상태를 저장하는 방법이다. 사용자가 웹사이트에 로그인하면 서버는 해당 사용자를 식별할 수 있는 고유한 세션을 생성한다. 이 세션에는 사용자 ID, 권한, 로그인 시간 등 사용자의 상태 정보가 포함될 수 있다. 세션의 주요 특징은 다음과 같다.

  • 서버 측 저장 : 세션 정보는 서버의 메모리나 데이터베이스에 저장된다.
  • 세션 ID : 각 세션은 고유한 세션 ID로 식별된다. 이 세션 ID는 클라이언트에게 쿠키로 전송되어 이후 요청에 포함된다.
  • 유효 기간 : 세션은 일정 시간이 지나면 자동으로 만료될 수 있다. 이는 보안 강화를 위해 설정된다.
  • 보안성 : 세션 ID가 유출되면 보안 문제가 발생할 수 있으므로, 세션 관리에 주의가 필요하다.

쿠키(Cookie)

쿠키는 클라이언트 측에서 상태 정보를 저장하는 방법이다. 웹 서버는 클라이언트의 브라우저에 소량의 데이터를 쿠키 형태로 저장하고, 클라이언트는 이후 요청 시 이 쿠키를 서버에 전송한다. 쿠키의 주요 특징은 다음과 같다:

  • 클라이언트 측 저장 : 쿠키는 클라이언트의 브라우저에 저장된다.
  • 키-값 쌍 : 쿠키는 키-값 쌍 형태로 데이터를 저장하며, 주로 세션 ID와 같은 정보를 포함한다.
  • 유효 기간 : 쿠키는 설정된 유효 기간 동안 브라우저에 유지되며, 만료 시간이 지나면 삭제된다.
  • 자동 전송 : 클라이언트가 동일한 도메인에 요청을 보낼 때마다 브라우저는 자동으로 쿠키를 포함시켜 서버에 전송한다.



2. 세션과 쿠키 동작 흐름

웹 애플리케이션에서 클라이언트와 서버 간의 인증 방식 중 하나로 세션-쿠키 인증 방식이 자주 사용된다. 아래는 세션-쿠키 인증 방식의 전반적인 흐름이다.

1. 사용자 로그인 요청

- 사용자가 로그인 폼에 사용자 이름과 비밀번호를 입력하고, 이 정보를 서버로 전송한다.

2. 서버에서 사용자 인증

- 서버는 전송된 사용자 이름과 비밀번호를 데이터베이스와 비교하여 사용자를 인증한다.
- 인증에 성공하면 서버는 세션을 생성한다. 이 세션에는 사용자의 상태 정보(예: 사용자 ID, 권한 등)가 포함된다.

서버측 코드
const express = require('express');
const bcrypt = require('bcryptjs');
const session = require('express-session');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());
app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: true }));

// 가상의 사용자 데이터베이스
const users = [
  { id: 1, username: 'user1', password: '$2a$10$V6F/7T/o0H1jVz5xZ6Jv1OKe4Cn/4qG/nSIk7cC4j9HLqjCJ5eCqm' } // 'password123'의 해시값
];

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);

  if (!user) {
    return res.json({ success: false, message: 'Invalid username or password' });
  }

  bcrypt.compare(password, user.password, (err, isMatch) => {
    if (isMatch) {
      req.session.userId = user.id;
      res.json({ success: true });
    } else {
      res.json({ success: false, message: 'Invalid username or password' });
    }
  });
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

3.세션 ID 생성 및 저장

- 서버는 세션을 생성한 후, 이 세션을 식별할 수 있는 고유한 세션 ID를 생성한다.
- 이 세션 ID는 서버의 세션 저장소(메모리, 데이터베이스 등)에 저장된다.
- 위 서버측 코드에서 express-session 미들웨어가 세션 ID를 생성하고, 메모리에 저장한다.

4.클라이언트에게 쿠키로 세션 ID 전송

- 서버는 생성된 세션 ID를 클라이언트에게 쿠키로 전송한다. 이 쿠키는 HTTP 응답 헤더에 포함되어 있다.
- 쿠키는 브라우저에 저장되고, 설정된 유효 기간 동안 유지된다.
- express-session 미들웨어가 이 작업을 자동으로 처리한다.

5.클라이언트의 요청에 세션 ID 포함

- 클라이언트(브라우저)는 이후 서버에 요청을 보낼 때마다 쿠키에 저장된 세션 ID를 함께 전송한다. 이는 자동으로 이루어진다.

6.서버에서 세션 ID 확인

- 서버는 클라이언트의 요청을 받을 때, 전송된 쿠키에서 세션 ID를 확인한다.
- 서버는 이 세션 ID를 세션 저장소에서 찾아, 해당 세션에 저장된 사용자 상태 정보를 로드한다.

7.요청 처리 및 응답 전송

- 서버는 세션 정보를 사용하여 클라이언트의 요청을 처리한다. 예를 들어, 사용자가 로그인한 상태인지 확인하고, 권한에 따라 접근을 허용하거나 거부할 수 있다.
- 처리 결과는 HTTP 응답으로 클라이언트에게 전송된다.
app.get('/protected', (req, res) => {
  if (!req.session.userId) {
    return res.status(401).json({ message: 'Unauthorized' });
  }
  res.json({ message: 'Welcome to the protected route, user ' + req.session.userId });
});

8.세션 종료

- 사용자가 로그아웃을 요청하면, 서버는 세션 저장소에서 해당 세션을 삭제하고, 클라이언트에게 세션 쿠키를 만료시켜 더 이상 유효하지 않도록 한다.
- 세션의 유효 기간이 만료되면, 서버는 자동으로 세션을 삭제할 수도 있다. (만들기 나름)
app.post('/logout', (req, res) => {
  req.session.destroy(err => {
    if (err) {
      return res.status(500).json({ message: 'Logout failed' });
    }
    res.clearCookie('connect.sid');
    res.json({ message: 'Logout successful' });
  });
});