이번에는 이전 게시글에서 '쿠키'를 통해 로그인한 사용자 이름을 저장하는 것을 구현했다면 이번에는 '세션'을 이용해 본다.

- 쿠키 : 클라이언트쪽에 저장되어 보안성이 좋지 않음, 데이터의 수정이 될 수 있음

- 세션 : 서버쪽에 저장되어 쿠키보다 보안이 좋음

> 세션으로 구현하기 위해 랜덤 세션 id를 생성하고 세션 객체에 해당 랜덤 id를 키값으로 필요한 데이터를 담아두고

> 쿠키에 해당 랜덤 세션 키를 저장하는 방식으로 구현한다.

EX)

<app.js>

const http = require('http');
const fs = require('fs');
const url = require('url');
const qs = require('querystring');

const parseCookie = (cookie = '') => {
    // name=hyr;expires=ggg
    // [ name=hyr, expires=ggg]
    return cookie.split(';')
        // [ [name, hyr], [expires, ggg] ]
          .map(e => e.split('='))
          .reduce((acc, [key, val]) => {
              acc[key] = decodeURIComponent(val);
              return acc;
          }, {});
}

// 세션 객체 생성(서버 메모리에 기억)
let session = {

}

const server = http.createServer((req, res) => {
    let cookieStr = req.headers.cookie;
    let cookies = parseCookie(cookieStr);

    if(req.url.startsWith('/login')){
        let { query } = url.parse(req.url);
        let reqParams = qs.parse(query);

        // random int 값 생성
        let randomInt = +new Date();
        let expires = new Date();
        expires.setMinutes(expires.getMinutes() + 5);

        // randomInt 키값을 갖는 데이터를 session 객체에 동적 추가해줌
        session[randomInt] = {
            name : reqParams.name,
            expires
        };

        res.writeHead(302, {
            Location : '/',
            // session 키값을 쿠키에 저장해 놓는다.
            'Set-Cookie' : `sessionId=${randomInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`
        });
        res.end();
    } else if(cookies.sessionId && session[cookies.sessionId].expires > new Date()) {
    	// 쿠키에 저장한 랜덤세션id가 존재하면서 유효시간이 남아있는 경우 접근
        res.writeHead(200, {'Content-Type' : 'text/html; charset=utf-8'});
        res.end(`<h1>${session[cookies.sessionId].name}님 환영합니다.`);
    } else { // login page
        fs.readFile('./server2.html', (err, data) => {
            res.end(data);
        });
    }
});

server.listen(8082, () => {
    console.log('8082 server is listening');
});

server.on('error', (error) => {
    console.error(error);
});

이번에는 쿠키와 세션에 서버 데이터를 담아 전달하는 방법에 대해 알아보겠습니다.

1. 개념 : 쿠키와 세션 모두 사용자의 데이터를 담을 수 있습니다. 하지만 가장 큰 차이점은

쿠키는 클라이언트에 쿠키가 저장이 되어 보안에 취약합니다.

세션은 서버에 저장되어 쿠키에 비해 보안적으로 안전합니다.

1. 쿠키 저장해 보기

// http 모듈 import
const http = require('http');
// 미리 생성한 html 파일을 읽기 위한 fs 모듈 임포트
const fs = require('fs');

const server = http.createServer((req, res) => { // req : 요청, res : 응답
    // 쿠키를 지정 : 키 = 값 형식으로 ; 를 기준으로 설정
    res.writeHead(200, {'Set-Cookie' : 'mycookie=value1'});
    res.writeHead(200, {'Set-Cookie' : 'mycookie2=value2'});
    
    res.end('cookie save test');
});

server.listen(8081, () => {
    console.log('8081 server is lisening');
});

node app.js 로 서버 실행 후 http://localhost:8081/ 로 브라우저를 열고 F12 개발자 도구를 켠 다음 'application'탭을 보면 설정한 쿠키값들이 보임을 알 수 있다.

mycookie = value1

mycookie2 = value2

 

이번엔 쿠키를 이용해 간단한 로그인을 구현해 보도록 하겠다.

로그인 페이지에서 입력한 사용자의 이름을 쿠키에 name=hyr 처럼 저장한 후 쿠키값이 있을 경우 hyr님 반갑습니다.를 응답한다.

<app.js>

// http 모듈 import
const http = require('http');
// 미리 생성한 html 파일을 읽기 위한 fs 모듈 임포트
const fs = require('fs');
const url = require('url');
const qs = require('querystring');

// 쿠키 파싱 함수
const parseCookies = (cookie = '') => {
    // cookie => mycookie=value1;mycookie2=value2
    
    // eachCookies = [mycookie=value1, mycookie2=value2]
    let eachCookies = cookie.split(';');
    // [ [mycookie, value1], [mycookie2, value2] ]
    return eachCookies.map(e => e.split('='))
                      .reduce((acc, [key, val]) => { // acc : 누적
                          acc[key.trim()] = decodeURIComponent(val); // acc에 동적으로 key값에 value추가
                          return acc;
                      }, {});    
}
    
const server = http.createServer((req, res) => { // req : 요청, res : 응답
    // 쿠키 접근(req.headers.cookie)
    console.log(req.headers.cookie); // 문자열이기 때문에 파싱이 필요
    
    // 쿠키 파싱 함수를 통해 쿠키객체 얻어옴
    const cookies = parseCookies(req.headers.cookie);
  
    // req.url > 요청한 url 주소가 담겨있다.
    if(req.url.startsWith('/login')){ // /login으로 시작하는 url요청일 경우
        // http://localhost:8081/login?name=sooingkr 에서 ?name=sooingkr 부분인 쿼리스트링 부분을 가져온다.
        // 해당 정보가 객체로 query에 들어오게 됨
        const { query } = url.parse(req.url); 
        const { name } = qs.parse(query); // querystring 모듈로 name값을 파싱함

        // 저장할 쿠키 데이터의 유효시간을 지정하기 위함
        const expires = new Date();
        expires.setMinutes(expires.getMinutes() + 5); // 제한 시간 설정
        res.writeHead(302, // 302 코드 > redirection코드로 Location에 지정한 곳으로 리다이렉션한다. 
            {
                Location : '/',
                // expire 유효시간 Http통신 요청만 가능, / 요청에 대해서만 등 다양한 옵션을 설정할 수 있다.
                'Set-Cookie' : `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`
            }
        );

        res.end('<p>end</p>'); // 요청 응답 끝
    } else if(cookies.name) { // 로그인을 통해 쿠키에 name값이 존재하면
        
        res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'});
        // 쿠키에 저장된 name값을 응답
        res.end(`${cookies.name}님 안녕하세요`);
    } else { // 로그인 페이지
        // 로그인 페이지 html 을 읽어 로그인 페이지로 이동
        fs.readFile('./server2.html', (err,data) => {
            res.end(data);
        });
    }
});

server.listen(8081, () => {
    console.log('8081 server is lisening');
});

 

<server2.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>로그인 페이지</title>
</head>
<body>
    <h1>로그인페이지 입니다.</h1>
    <form action="/login" method="GET">
        <input type="text" id="name" name="name" />
        <button type="submit">로그인</button>
    </form>
</body>
</html>

<결과>

로그인 페이지(server2.html)

로그인 후 화면

 

세션은 다음 페이지에서 이어 설명하도록 하겠습니다.

 

- express 를 사용해 편리하게 서버를 구성할 수 있지만, 그전에 util모듈을 이용해 서버를 구성해보자.

1. text/html로 응답

// http 모듈 임포트
const http = require('http');

const server = http.createServer((req, res) => { // req : 요청정보, res : 응답정보
    console.log('server start');

    // 응답 Header정보 설정
    // 1 파라미터 > 응답 상태(status) ex) 200 : 성공 코드
    // 2. Content-Type 을 text/html charset=utf-8로 지정해 한글이 깨지지 않도록 함
    res.writeHead(200, {'Content-Type' : 'text/html; charset=utf-8'});

    res.write('<h1>응답할 text/html 문자열</h1>');
    res.write('<p>여러번 호출할 수 있음</p>');

    res.end('<p>응답의 끝임을 알림</p>');
});

server.listen(8081, () => { // 8081 포트로 서버 리스닝
    console.log('server 8081 port is listening');
});

// 서버 에러 응답 이벤트 리스너
server.on('error', (error) => {
    console.error(error);
})

http://localhost:8081/ 호출 결과>

이처럼 <h1>응답할 text/html 문자열</h1> 처럼 text/html을 직접 write해서 응답할 수도 있지만 html 파일을 미리 생성해 놓고 읽어서 응답할 수도 있다.

 

2. html 파일을 미리 생성하고 html페이지 응답하기

<app.js>

// http 모듈 import
const http = require('http');
// 미리 생성한 html 파일을 읽기 위한 fs 모듈 임포트
const fs = require('fs');

const server = http.createServer((req, res) => { // req : 요청, res : 응답
    // 현재 경로의 server1.html 파일 읽기
    fs.readFile('./server1.html', (err, data) => {
        if(err) throw err; // 실패 예외처리
        // 읽은 파일 내용을 응답
        res.write(data);
    });
});

server.listen(8081, () => {
    console.log('8081 server is lisening');
});

<server1.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FILE로 읽기</title>
</head>
<body>
    <h1>server1.html 페이지 입니다. 반갑습니다.</h1>
</body>
</html>

+ Recent posts