Nodejs/Server

Server의 이해 - Cookie #1

Sila 2022. 2. 7. 17:39

가끔 인터넷을 돌아다니다보면 쿠키를 삭제하라는 문구를 본 적이 있다.

 

브라우저는 데이터를 저장하는 기능도 가지고 있는데, 쿠키는 브라우저가 저장하는 데이터 중 하나다.

 

개발자도구 > 어플리케이션 > 스토리지 > Cookies 탭을 들어가보면

 

브라우저가 저장하고 있는 쿠키들과 그 property들을 볼 수 있다.

 

이런 데이터가 계속해서 쌓이기 때문에 브라우저를 오래 사용하다보면 용량이 늘어나게 된다.

 

 

그럼에도 이 쿠키라는게 왜 필요한가?

 

서버가 브라우저에서 요청을 받을 때, 한 컴퓨터를 여러 명이 사용하는 경우 누가 요청을 보내는지 알 수 없다.

 

그래서 사용자에 따라 다른 응답을 줄 수 있도록 변수를 추가해주는 것인데, 이 추가해주는 변수가 쿠키이다.

 

 

브라우저의 Cookie를 확인하는 법

 

이제부터는 헤더에 쿠키를 집어넣는 방법을 알아보고 넣은 쿠키를 이용해 간단한 로그인 기능을 구현해보자.

 

 

1. 쿠키 삽입

우선 새로 server.js 파일과 index.html 파일을 만들고 메인 페이지를 불러올 때 잘 작동을 하는지 한 번 확인을 해준다.

 

/*  server.js  */

// nunjucks, express setup

const express = require('express')
const app = express()
const nunjucks = require('nunjucks')

app.set('view engine', 'html')
app.use('express.urlencoded({extended:true}))

nunjucks.configure('views', {express:app})

// 라우터 - 메인 페이지

app.get('/', (req, res) => {
   res.render('index.html')
}

// 서버 구동

app.listen(3000, () => {
   console.log('서버 구동')
}

 

/*  index.html  */

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello</h1>
</body>
</html>

이렇게 하고 localhost:3000 으로 들어가서 쿠키 목록을 확인해보면 다음과 같이 아무것도 없음을 알 수 있다.

 

 

이제 라우터에 쿠키를 넣는 것을 연습해보자.

 

index.html을 렌더링하면서 동시에 쿠키를 헤더에 넣어주는 것을 응답으로 넣어줄 것이다.

 

코드를 다음과 같이 수정해보자.

 

/* server.js  */

app.get('/', (req, res) => {
   res.render('index.html')
   res.setHeader('headerKey', 'headerValue')
   res.setHeader('Set-Cookie', 'token=1')
   console.log(req.headers.cookies)
}

 

다시 한 번 웹 페이지를 불러오면 다음과 같이 응답 헤더에 headerKey와 Set-Cookie가 추가되었음을 볼 수 있다. 

 

응답 헤더에 요소 추가

한 편, 어플리케이션 탭에서 쿠키 목록을 보면 쿠키의 이름과 값을 브라우저가 인식해 저장했음을 알 수 있다.

 

단, headerKey: HeaderValue는 문법이 다르기 때문에 응답 헤더의 요소로 나타날 뿐 쿠키로 취급되지 않는다.

 

쿠키를 생성하고 싶으면 다음과 같은 일정한 문법을 따라야 한다.

 

res.Setheader('Set-Cookie', '<cookie-name>=<cookie-value>')

 

name=value 형태를 가진 'token=1'만이 쿠키 목록에 나타남을 알 수 있다. 

 

쿠키가 추가된 모습

 

cf) 쇼핑몰 등에서 팝업뜨고 일주일 간 안 보기 같은 기능도 쿠키를 이용하는데, 쿠키의 기간을 정해주고 싶다면

 

Expires/Max-Age를 설정해주면 된다. (쿠키의 유지 기간)

 

 

2. html에서의 쿠키 인식

js는 명령어를 통해 이렇게 생성해준 쿠키에 접근할 수 있다.

 

이를 이용해 우선 html에서 쿠키를 인식하고, 쿠키의 값에 따라 다르게 반응하도록 코드를 짜보자.

 

 

좀 전에 쿠키를 생성하는 문법을 생각해보면 쿠키의 이름과 쿠키의 값이 있고, 그 둘은 '='을 기준으로 나뉘어 있다.

 

따라서 쿠키의 값 혹은 쿠키의 이름만을 가져오려면 '='을 기준으로 쪼개 필요한 값만을 취하면 된다.

 

html에 다음과 같이 script를 추가해보자.

 

/* index.html  */

<script type='text/javascript'>

    //  document.cookie = 'token=1'
    
    let cookie_index = document.cookie.split('=')
    //  split을 이용해 자르면 결과물은 배열로 나타난다.
    //  배열의 첫 번째 요소는 쿠키의 이름, 두 번째 요소는 쿠키의 값이 된다.
    
    if (cookie_index[0] === 'token' && cookie_index[1] === '1') {
        alert('인증된 사용자입니다.')
    }
    
</script>

 

html 내의 script 요소에서 document의 쿠키를 가져온 후, 그걸 쪼갠 값을 cookie_index라는 변수에 넣어주었다.

 

그럼 그 결과물로 '='을 기준으로 쪼갠 두개의 문자열이 나오게 된다.

 

cookie_index=['token', '1']

 

cookie_index[0] = 'token', cookie_index[1]='1'

 

그 후 조건문을 줘서 각 값이 일치할 경우 인증된 사용자라는 알람이 뜨도록 한 후 실행해보면 조건을 만족하므로

 

인증된 사용자라는 알림이 뜨는 것을 확인할 수 있다.

 

다음과 같이 쿠키를 html에서 수정할 수도 있다.

 

/* index.html  */

<script type='text/javascript'>
	document.cookie='token=0'
    let cookie_index = document.cookie.split('=')
   
    
    if (cookie_index[0] === 'token' && cookie_index[1] === '1') {
        alert('인증된 사용자입니다.')
    }
    
    else {
        alert('인증되지 않은 사용자입니다.')
    }
    
</script>

 

쿠키 값을 token=0으로 바쭤주면 cookie_index[0]은 0이 되고 조건을 만족하지 못하게 되어 else문이 실행된다.

 

3. 쿠키를 이용한 로그인/로그아웃

 

지금까지 배운 것들을 응용해 로그인, 로그아웃 기능을 구현해보자.

 

우리가 아이디와 패스워드를 입력하고 요청을 전송했을 때 (쿠키),

 

서버가 db에 가지고 있는 데이터와 비교해 일치한다면 로그인이 진행되고,

 

그렇지 않다면 실패하는 방식으로 코드를 짜주면 된다.

 

(동시에 이에 맞춰 불러오는 html도 달라져야 한다.)

 

시작하기 전에 개발자 도구를 열어 어플리케이션 탭으로 들어가 지금까지 만든 쿠키를 전부 삭제하고 시작한다.

 

우선 js 파일에 잠시 db의 역할을 해줄 전역 변수를 하나 설정하자.

 

/*  server.js  */

let user = {
    userid : 'lifereset',
    userpw: '1234',
    username:'lsj'
}

이에 따르면 우리가 전역 변수 user와 동일하게

 

사용자가 userid에 'lifereset', userpw에 '1234'를 입력해줬을 때만 로그인이 진행된다.

 

3.1 웹 페이지 초기값 설정

처음 메인 페이지로 들어갔을 때는 우리가 쿠키를 만든 적이 없으므로 쿠키가 없는 상태이다.

 

(이 경우, console.log(req.headers.cookie)의 결괏값은 undefined가 출력된다.)

 

따라서 쿠키값이 undefined일 때의 응답을 미리 따로 만들어놓고 시작을 해야한다.

 

라우터에서 메인 페이지에 대한 코드를 다음과 같이 수정하면 된다.

 

app.get('/', (req, res) => {
    if (req.headers.cookie === undefined) {
        res.render('main.html')
    }
}

 

이제 메인 페이지와 로그인 페이지에서 불러올 html을 만든다.

 

/*  main.html  */

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>
        <a href="/">logo</a>
    </h1>

    <ul>   
        <li><a href="/login">로그인</a></li>
    </ul>
</body>
</html>

 

/*  login.html  */

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
        <a href="/">logo</a>
    </h1>
    <form method="post" action="/login">
        아이디: <input type="text" name="userid">
        패스워드: <input type="text" name="userpw">
        <input type="submit" value="로그인">
    </form>
</body>
</html>

메인 페이지에서 로그인 버튼을 눌러 로그인 페이지로 이동 후, id와 pw를 입력해 제출하면,

 

서버가 가진 데이터와 비교해 일치하는지 판별 후, 일치 여부에 따라 다른 응답을 돌려주도록 할 것이다.

 

라우터에 다음과 같이 추가하자.

 

/*  server.js  */

app.post('/login', (req, res) => {
    const userid = req.body.userid
    const userpw = req.body.userpw

    if (user.userid === userid && user.userpw === req.body.userpw) {
       console.log('로그인 성공')
       res.setHeader(`set-Cookie`, `login= ${userid}`) // 입력값을 쿠키로 생성한다.
       res.redirect('/')
       }
       
    else {
       console.log('로그인 실패')
       res.redirect('/login')
    }
})

사용자가 id와 pw를 입력해 post로 제출하면 서버는 그걸 받아 가진 데이터의 id와 pw와 일치하는지를 판별한다.

 

같다면 (상기 if문을 만족한다면) 로그인 성공 메시지가 출력되고 메인 페이지로 리다이렉트 된다.

 

다르다면 로그인 실패 메시지가 출력되고 다시 로그인 페이지로 돌아간다.

 

3.2 로그인 성공 시 돌아갈 메인 페이지 만들기

메인 페이지는 이미 만들었는데 이게 무슨 소린가 싶겠지만

 

우리는 쿠키가 undefined인 경우에 대해서만 응답을 주도록 만들었기 때문에

 

이 상태에서 로그인을 시도해 성공하고 메인 페이지로 리다이렉트 될 경우,

 

메인 페이지에서 주는 응답이 존재하지 않아 계속 응답 대기중인 상태가 유지된다.

 

 

이를 해결하기 위해서는 쿠키가 undefined가 아닌 경우에 대한 응답 코드를 라우터에 작성하면 된다.

 

메인 페이지에 대한 라우터 코드를 다음과 같이 수정한다.

 

/*  server.js  */

app.get('/', (req, res) => {
   if (req.headers.cookie === undefined) {
      res.render('index.html')
  }
  // 쿠키가 undefined일 경우
  
  else {
      let cookie = req.headers.cookie.split('=')
      let userid = cookie[1]
      
      res.render('index.html')
    }
})

 

4. 로그인/로그아웃에 따라 다른 렌더링 가져오기

이제 메인 페이지에서 로그인이 되어 있는 경우와 그렇지 않는 경우를 나눠

 

각각의 경우 메인 페이지에서 다른 html 요소들을 렌더링하는 기능을 구현해보도록 하자.

 

우선 라우터의 메인 페이지 부분에 로그인 여부를 알려줄 boolean 변수를 메인 페이지 라우터에 추가한다.

 

 

변수 isLogin은 로그인이 되었을 때 true, 그렇지 않을 때 false값을 가지게 될 것이다.

 

이 isLogin의 true/false 값을 인식해 각각의 경우에 main.html에서 다른 요소들을 렌더링할 것이다.

 

라우터-메인페이지를 다음과 같이 수정해보자. 아까 cookie를 이름과 값으로 쪼갠 것과

 

동일한 방법을 사용하면 된다.

 

4.1 로그인 여부에 따라 달라지는 변수 생성, html에 전달

app.get('/', (req, res) => {
    let isLogin = false
    
    if(req.headers.cookie === undefined) {
        res.render('index.html')
    }
    
    else {
        let cookie = req.headers.cookie.split('=')
        let userid = cookie[1]
        
        if(userid === 'lifereset') {
            isLogin = true
        }
        
        res.render('index.html', {
            userid: userid,
            isLogin:isLogin
        })
    }
})

 

받은 쿠키값을 쪼개 userid의 값만을 가져온 후, 그것을 서버가 가진 userid와 동일한지 대조해본다.

 

동일하다면 (userid === 'lifereset' 가 true라면) 변수 isLogin의 값을 true로 변경한 후,

 

userid와 isLogin의 이름과 값을 html에 전달해준다.

 

4.2 html에서 변수의 참/거짓을 반영하는 조건문 활용

이제 isLogin의 참/거짓에 따라 다른 element들을 렌더링하도록 html을 조작해줄 것이다.

 

/*  main.html  */

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>
        <a href="/">logo</a>
    </h1>

    <ul> 
    {% if isLogin %}
        <!--로그인 되었을 때 코드 실행 영역 -->
        <li>{{userid}}님 환영합니다.</li>
        <li><a href='#'>logout</a></li>
        <li><a href='#'>profile</a></li>
    
    {% else %}
    <!-- 로그인 되지 않았을 때 코드 실행 영역 -->
        <li><a href="/login">로그인</a></li>
    {% endfor %}
    </ul>
    
</body>
</html>

 

html에서도 js와 비슷하게 if문을 사용할 수 있다.

 

{% %} 를 괄호로 쓰고 원하는 대로 문법을 맞춰서 써주면 된다.

 

if ~~와 else 는 조건문, endfor은 조건문의 범위를 거기까지로 한정한다는 것을 의미한다. 

 

여기까지 한 후 다시 서버를 실행 해, 메인페이지를 열고, 로그인을 해 다시 메인 페이지로 돌아오면

 

로그인 하기 전, 후 웹 페이지의 렌더링이 달라졌음을 확인할 수 있다.

 

다음 포스팅에선 로그아웃 기능과 프로필 페이지를 구현해보도록 하자.

 

'Nodejs > Server' 카테고리의 다른 글

Session #2 - 미들웨어  (0) 2022.02.13
Session #1  (0) 2022.02.13
Server의 이해 - Cookie #2  (0) 2022.02.08
JavaScript의 활용 - 게시판 서버 만들기 #2  (0) 2022.02.06
Javascript의 활용 - 게시판 서버 만들기 #1  (0) 2022.02.06