본문 바로가기

Programming/Node.js

5. http 모듈로 서버 만들기 (3) - 쿠키와 세션의 이해 [7]

node js logo image

 

 

 

 

앞서 작성했던 코드로 서버를 실행하고, 사용자 이름을 넣어 쿠키를 동작해 보도록 하겠습니다. cookie2.js를 실행하고, URL 입력창에 http://localhost:8084를 입력해 봅시다. 그러면 아래와 같은 화면을 만날 수 있습니다.

 

 

 

 

이제 여기에 적당한 값을 넣고 [LOGIN] 버튼을 클릭하면, 로그인 처리를 하고 화면에 환영 인사를 출력합니다. 그런데 개발자 도구의 Application 탭에서 쿠키를 확인해 보겠습니다. 사실상 쿠키가 그대로 노출되고 있는 상태입니다. 보안상, 민감한 정보는 쿠키에 넣지 않는 것이 원칙이고 보관하는 방법도 달라야 합니다.

 

 

 

 

그럼 다음 예제에서 우리가 작성했던 코드를 수정해서 서버가 사용자의 정보를 관리하도록 만들어보겠습니다. 여기서 사용하는 방식이 바로 세션 쿠키 방식입니다. 방식을 요약하자면, 직접 쿠키에 이름을 담아서 보내지 않고 일종의 숫자 값을 보내는 것입니다. 서버에 사용자 이름과 만료 시간과 같은 정보를 저장하고, 클라이언트와는 세션 아이디로만 소통하는 것이죠. 

 

 

[session.js]

const http = require('http');
const fs = require('fs').promises;
const path = require('path');


const parseCookies = (cookie = '') => 
    cookie
        .split(';')
        .map(v => v.split('='))
        .reduce((acc, [k, v]) => {
            acc[k.trim()] = decodeURIComponent(v);
            return acc;
        }, {});

const session = {};


http.createServer(async (req, res) => {
    const cookies = parseCookies(req.headers.cookie);

    // 주소가 /login으로 시작하는 경우
    if(req.url.startsWith('/login')) {
        const url = new URL(req.url, 'http://localhost:8085');
        const name = url.searchParams.get('name');
        const expires = new Date();
        // 쿠키의 유효 시간은 현재 시각 + 5분으로 설정한다.
        expires.setMinutes(expires.getMinutes() + 5);
        const uniqueInt = Date.now();
        session[uniqueInt] ={
            name,
            expires,
        };
        res.writeHead(302, {
            Location: '/',
            'Set-Cookie': `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
        });
        res.end();

        // 세션 쿠키가 존재하고 만료 기간이 지나지 않았다면
    } else if (cookies.session && session[cookies.session].expires > new Date()) {
        res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
        res.end(`${session[cookies.session].name}님 안녕하세요`);
    } else { // 주소가 /이면서 name이라는 쿠키가 없는 경우
        try {
            const data = await fs.readFile(path.join(__dirname, 'cookie2.html'));
            res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
            res.end(data);
        } catch (err) {
            res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
            res.end(err.message);
        }
    }

})
    .listen(8085, () => {
        console.log('8085번 포트 서버 대기 중');
    });

 

 

위와 같이 일부 코드를 변경하고, 동일한 방식으로 실행 테스트를 진행해 봅시다. 아래와 같이 session에 저장한 변수를 통해서 소통하게 됩니다. 

 

 

 

 

 

세션 아이디는 쿠키를 이용하지 않아도 되지만, 쿠키를 사용하는 방식이 가장 간단하기 때문에 많이 사용하고 있는 방식입니다. 이러한 쿠키를 세션 쿠키로 칭하죠. 물론 이런 예제의 방식은 메모리에 저장된 변수는 초기화 됩니다. 서버 메모리 부족 시에 세션을 저장하지 못하기도 하구요. 그래서 일반적으로 사용하는 DB가 레디스(Redis)나 멤캐시드(Memcached)입니다. 

 

또한 예제는 실제 사용할 수 있는 레벨은 아니므로 다른 모듈을 사용해 구현해야 합니다.