본문 바로가기
경일/nodejs

[nodejs] 쿠키 이용해서 로그인 / 로그아웃 해보기

by dev_kong 2022. 2. 7.
728x90
728x90

0. 목차

1. 개요

2. 세팅

3. 페이지구성

4. 기능구현

5. 멍청이짓 수정

6. user data 2개 이상일 때

5. 멍청이짓 수정2

 

1. 개요

https://kong-dev.tistory.com/129

 

[nodejs] 쿠키 먹는거 말고

0.목차 1. http 통신 2. 브라우저 3. 쿠키 1. http 통신 서버에 요청을 보낼때는 일정한 규격에 따라 요청을 해야한다. 그런데 이 규격만 맞춰 준다면 새로운 내용을 작성해서 보내줄 수도 있다. 이제

kong-dev.tistory.com

쿠키가 뭔지 대충 알았으니까

쿠키를 이용해서 로그인과 로그아웃기능을 만들어볼거다.

 

2. 세팅

세팅을 먼저하자.

우선 필요한 라이브러리는 express랑 nunjucks 인듯하다.

그리고 exprss 업데이트 사용할수 있는 body-parser 기능 까지 주욱 해버릴거임

 

$ npm init -y
$ npm install express nunjucks

 

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

const app = express();

app.set('view engine', 'html');
nunjucks.configure('views', { express: app });

app.use(express.urlencoded({ extended: true }));

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

app.listen(3000);

 

뚝-딱

3. 페이지 구성

오늘 만들 페이지는 총 3개다.

 

index,

login,

profile

 

그런데 3갠데 3개가 아닌 듯한 느낌으로 만들거다.

 

살면서 그림판 이렇게 열심히 써본거 처음임.

 

대충 이런식으로 만들건데,

관건은 로그인이 되었냐 안되었냐에 따라

/ 에 get 요청을 보냈을 때 보여지는 화면이 달라져야 한다는거다.

 

이걸 쿠키를 이용해서 만들어볼거다.

4. 기능구현

4-1. 임시 데이터

아직 db는 안배웠으니까

server에다가 임시로 회원 데이터 하나를 만들어서 그걸 사용해야한다.

 

const user = {
  id: 'kong1234',
  pw: '12345678',
  name: 'kong',
};

server.js 에다가 전역 변수로 하나 갖다 박음

 

4-2. Login

index.html

여기서 login을 누르면

이렇게 생긴 페이지로 이동한다 아주 이쁘다.

 

여기서 id와 pw 를 입력하고 로그인 버튼을 누르면

/login 으로 post 요청을 보내게 된다.

그럼 post 요청을 받은 웹서버는

입력된 id와 pw가 데이터에 있는것과 일치하는지 확인하고,

일치하면 로그인을 해주고

일치하지 않으면 로그인을 안시켜주면 된다.

아주 간단하다.

 

그럼 로그인이 됐는지 안됐는지 를 판단하는 기준을 뭐로 잡을 건지가 중요한데,

그게 바로 쿠키다.

 

id 와 pw 가 일치하면 브라우저에 쿠키 전달해주고,

브라우저는 쿠키의 여부로 로그인이 됐는지 안됐는지를 판단한다.

 

https://kong-dev.tistory.com/129

 

[nodejs] 쿠키 먹는거 말고

0.목차 1. http 통신 2. 브라우저 3. 쿠키 1. http 통신 서버에 요청을 보낼때는 일정한 규격에 따라 요청을 해야한다. 그런데 이 규격만 맞춰 준다면 새로운 내용을 작성해서 보내줄 수도 있다. 이제

kong-dev.tistory.com

쿠키 전달은 여기서 했었다.

 

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

  if (userid === user.id && userpw === user.pw) {
    res.setHeader('Set-Cookie', 'login=true');
  } else {
    res.setHeader('Set-Cookie', 'login=false');
  }

  res.redirect('/');
});

 

이렇게 일치하는 경우에는 login = true 로 쿠키를 보내준뒤

/ 으로 리다이렉트 처리를 해주고

일치하지 않으면 login = false 로 쿠키를 보내준 뒤

/ 로 리다이렉트 처리를 해준다.

 

일치하는 id 와 pw 를 입력한 경우의 쿠키
일치하지 않는 id와 pw를 입력한 경우의 쿠키 

 

이제 저 쿠키의 value 에 따라 / 에서 보여지는 구성이 달라져야한다.

 

경우의 수는 세가지이다.

로그인 시도를 하지 않은 경우

로그인에 성공한 경우

로그인에 실패한 경우

 

나는 server에서는 

로그인 시도를 한경우와 안한 경우 두가지의 케이스만 처리하고

 

로그인 성공과 실패에따른 결과는

index.html에서 nunjucks로 처리해보려고 한다.

 

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

  if (req.headers.cookie !== undefined) {
    const [, isLogin] = req.headers.cookie.split('=');
    const msg = 'login 실패';

    res.render('index.html', { user, isLogin, msg });
  }
});

 

  <ul>
      {% if isLogin %}
      <li><a href="/profile">profile</a></li>
      <li><a href="/logout">logout</a></li>
      {% else %}
      <li>
        <a href="/login">login</a>
      </li>
      {% endif %}
    </ul>

이렇게 해주면

될거 같지만 안된다.

 

isLogin의 데이터 타입이 boolean이 아니라 string 이기 때문에

isLogin이 false 라도 

nunjucks에서 확인할때는 'false' 의 truthy/ falsy 값을 판단하고,

빈 문자열이 아니기 때문에 true 로 판단하기 때문에

로그인이 실패하든 성공하든

전부 

이렇게 랜더된다.

 

그럼 어떻게 해결하지

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

  if (req.headers.cookie !== undefined) {
    const [, value] = req.headers.cookie.split('=');
    const msg = 'login 실패';
    let isLogin = false;

    if (value === 'true') {
      isLogin = true;
    }

    res.render('index.html', { user, isLogin, msg });
  }
});

app.get 부분을 이렇게 바꿔줌

쿠키의 밸류를 변수 value로 받고

isLogin이라는 변수에 false 값을 할당해준다.

그리고 value가 'true' 이면 

isLogin을 true로 변경해서 전달한다.

이렇게 해주니까

로그인 실패
로그인 성공

심심해서..

https://mozilla.github.io/nunjucks/templating.html#if

 

Nunjucks

Templating This is an overview of the templating features available in Nunjucks. Nunjucks is essentially a port of jinja2, so you can read their docs if you find anything lacking here. Read about the differences here. User-Defined Templates Warning nunjuck

mozilla.github.io

http://mozilla.github.io/nunjucks/templating.html#logic

 

Nunjucks

Templating This is an overview of the templating features available in Nunjucks. Nunjucks is essentially a port of jinja2, so you can read their docs if you find anything lacking here. Read about the differences here. User-Defined Templates Warning nunjuck

mozilla.github.io

nunjucks 공식문서 읽어보다가 발견함.

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

  if (req.headers.cookie !== undefined) {
    const [, isLogin] = req.headers.cookie.split('=');
    const msg = 'login 실패';

    res.render('index.html', { user, isLogin, msg });
  }
});
 {% if isLogin==='true' %} {{user.name}}님 환영합니다.
      <li><a href="/profile">profile</a></li>
      <li><a href="/logout">logout</a></li>
      {% elif isLogin==='false' or not isLogin %}
      <li>
        <a href="/login">login</a>
      </li>
      {% endif %}

이렇게 해줘도 똑같이 동작한다.

이게더 코드가 깔끔하니 이렇게 쓸거임

 

그리고 난 로그인 실패했을때는 로그인 실패했다는 알림이 뜨게 하고싶다.

  {% if isLogin==='false' %}
    <script>
      alert('{{msg}}');
    </script>
    {% endif %}

index.html head 에 nunjucks문법으로 server에서 전달받은 isLogin의 값이 

'false' 이면 server에서 전달받은 msg를 alert로 띄워준다.

 

server 에 있는 데이터와 일치하지않으면 이런 알림이 뜬다.

 

요렇게 해주면 login끝

 

4-3. /profile

이제 profile 이다.

성공적으로 login을 하고 

나오는 화면

여기서

profile 을 누르면

user의 정보가 나오도록 하고싶다.

 

app.get('/profile', (req, res) => {
  res.render('profile.html', { user });
});
  <body>
    <h1><a href="/">LOGO</a></h1>
    <ul>
      <li>id : {{user.id}}</li>
      <li>name : {{user.name}}</li>
    </ul>
  </body>

아주 간단하다.

요렇게 이쁘게 잘 나온다.

 

그런데 여기서 한가지 문제가 있다.

만약 어떤 이상한 사용자..가 

login을 안한채로 uri 에 쌩으로 profile입력하고 접속하면 어떻게 될까?

 

로그인을 안한채로 profile에 접속을 해도 똑같이 user를 전달하기에 server에 있는 데이터가

랜더되는것을 볼수 있다.

매우 곤란하다.

로그인이 안되어있을때는 profile에 접속하면 다시 / 으로 돌아가게끔 하면될거 같다.

 

app.get('/profile', (req, res) => {
  const cookie = req.headers.cookie;

  if (cookie === undefined) {
    res.redirect('/');
  } else {
    const [, isLogin] = cookie.split('=');
    if (isLogin === 'false') {
      res.redirect('/');
    } else if (isLogin === 'true') {
      res.render('profile.html', { user });
    }
  }
});

흠... 일단 잘되긴하는데,

여기서 뭔가 잘못만들었구나 라는걸 느꼈다.

그건 마지막에 한번에 수정하는걸로...

 

4-4. Logout

이제 로그아웃이다.

로그아웃은 간단하다.

쿠키를 삭제해주고 / 으로 돌려보내주면 된다.

 

app.get('/logout', (req, res) => {
  res.setHeader('Set-Cookie', 'login=true; Max-age=0');
  res.redirect('/');
});

 

이렇게 해주면 기존에 있던 쿠키가 삭제 되고

/ 으로 리다이렉트 되면서

로그아웃이 된다.

 

5. 멍청이짓 수정

ㅎ... 개멍청했다.

지금은 임시데이터에 user 정보가 하나 밖에 없어서

쿠키 값을 login=true 또는 login=false 로 전달해줘도 아무 상관이 없지만,

user 정보가 2개 이상만 되도 이 코드는 조진코드가 되버린다.

 

profile 을 만들면서 눈치 챘는데,

login 이 true 일때 user 정보를 전달해주는데,

어떤 user의 정보를 전달해줄지 알수가 없다.

여기서 수정을 하려면

login=userid 를 전달하도록 해주고

profile 을 눌렀을때는 쿠키값을 확인해서 

userid와 일치하는 데이터의 정보를 전달 해줘야된다....

ㅎㅎㅎ 

 

고칠 부분이 한두군데가 아닌데 위에서 부터 하나씩 해보자.... 후우.. 

 

const user = {
  id: 'kong1234',
  pw: '12345678',
  name: 'kong',
};
let isLogin = false;

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

const app = express();

app.set('view engine', 'html');
nunjucks.configure('views', { express: app });

app.use(express.urlencoded({ extended: true }));

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

  if (req.headers.cookie !== undefined) {
    const [, userid] = req.headers.cookie.split('=');
    const msg = 'login 실패';

    res.render('index.html', {
      userid, //
      isLogin,
      msg,
    });
  }
});

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

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

  if (userid === user.id && userpw === user.pw) {
    res.setHeader('Set-Cookie', `login=${user.id}`);
    isLogin = true;
  } else {
    res.setHeader('Set-Cookie', 'login=false');
  }

  res.redirect('/');
});

app.get('/profile', (req, res) => {
  if (req.headers.cookie === undefined) {
    res.redirect('/');
  } else {
    const [, userid] = req.headers.cookie.split('=');
    if (isLogin && userid === user.id) {
      res.render('profile.html', { user });
    } else {
      res.redirect('/');
    }
  }
});

app.get('/logout', (req, res) => {
  isLogin = false;
  res.setHeader('Set-Cookie', 'login=true; Max-age=0');
  res.redirect('/');
});

app.listen(3000);

 

수정한 전체 코드

생각보다 금방했다.

한 10분 정도 걸린듯..

원한대로 동작은 다 잘된다.

 

6. user data 2개 이상일때

생각보다 수정을 금방해버려서 해보고싶은게 생겨버렸다.

그.. user data 가 두개 이상일때...

해보고싶어짐..

 

나.. 잘 수 있을까..

 

6-1. user data 추가

const userList = [
  {
    id: 'kong1234',
    pw: '12345678',
    name: 'kong',
  },
  {
    id: 'pea1234',
    pw: '12345678',
    name: 'pea',
  },
];

배열로 넣었다.

mysql에서 데이터 받아올때 배열로 받아오니까.

나도 배열로 만듬

 

생각해보니 딱히 뭐 그렇게 추가할거 없다.

login 이랑 profile 부분만 신경쓰면 뭐 딱히..?

 

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

  userList.forEach((user) => {
    if (user.id === userid && user.pw === userpw) {
      res.setHeader('Set-Cookie', `login=${user.id}`);
      isLogin = true;
      break;
    } else {
      res.setHeader('Set-Cookie', 'login=false');
    }

  });
      res.redirect('/');

});

이렇게 하려고 했는데 

생각해보니 forEach는 break 안먹는다...

후우.. 그냥 for of 로 다시..

 

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

  for (const user of userList) {
    if (user.id === userid && user.pw === userpw) {
      res.setHeader('Set-Cookie', `login=${user.id}`);
      isLogin = true;
      break;
    } else {
      res.setHeader('Set-Cookie', 'login=false');
    }
  }
  res.redirect('/');
});

아주 잘된다.ㅎ

 

이제 profile

app.get('/profile', (req, res) => {
  if (req.headers.cookie === undefined) {
    res.redirect('/');
  } else {
    const [, userid] = req.headers.cookie.split('=');
    const user = userList.filter((v) => v.id === userid);
    if (isLogin && userid === user[0].id) {
      res.render('profile.html', { user: user[0] });
    } else {
      res.redirect('/');
    }
  }
});

filter 이용해서 일치하는 데이터 찾아내서 배열에 담는다.

id가 중복되는 일은 없을 거니까

user의 length 는 1일 거니까 그냥 0번째 값 때려박아주면 된다.

 

6. 멍청한짓 수정 2

ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

하나씩 발견되는거 킹받넼ㅋㅋㅋㅋㅋ

 

그렇게 중요한건 아닌데,

서버를 껐다가 키면,

로그인 쿠키가 남아있음에도

로그인이 안된것 처럼 화면이 렌더된다.

왜지... 생각해보니까

isLogin 전역변수로 false 때려박아놔서 그럼 ..ㅎ 

후우..

 

찐찐막 수정이길 바란다..

 

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

  if (req.headers.cookie !== undefined) {
    const [, userid] = req.headers.cookie.split('=');
    const msg = 'login 실패';
    let isLogin = false;

    const check = userList.filter((v) => v.id === userid).length;
    if (check) {
      isLogin = true;
    }
    res.render('index.html', {
      userid, //
      isLogin,
      msg,
    });
  }
});
app.get('/profile', (req, res) => {
  if (req.headers.cookie === undefined) {
    res.redirect('/');
  } else {
    const [, userid] = req.headers.cookie.split('=');
    const user = userList.filter((v) => v.id === userid);
    if (user.length) {
      res.render('profile.html', { user: user[0] });
    } else {
      res.redirect('/');
    }
  }
});

/ 부분과

/profile 

부분을 수정하고

나머지 부분에서 isLogin 건드는걸 다 없앴더니

자아ㅏ아아알 된다.

 

const userList = [
  {
    id: 'kong1234',
    pw: '12345678',
    name: 'kong',
  },
  {
    id: 'pea1234',
    pw: '12345678',
    name: 'pea',
  },
];

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

const app = express();

app.set('view engine', 'html');
nunjucks.configure('views', { express: app });

app.use(express.urlencoded({ extended: true }));

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

  if (req.headers.cookie !== undefined) {
    const [, userid] = req.headers.cookie.split('=');
    const msg = 'login 실패';
    let isLogin = false;

    const check = userList.filter((v) => v.id === userid).length;
    if (check) {
      isLogin = true;
    }
    res.render('index.html', {
      userid, //
      isLogin,
      msg,
    });
  }
});

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

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

  for (const user of userList) {
    if (user.id === userid && user.pw === userpw) {
      res.setHeader('Set-Cookie', `login=${user.id}`);
      break;
    } else {
      res.setHeader('Set-Cookie', 'login=false');
    }
  }
  res.redirect('/');
});

app.get('/profile', (req, res) => {
  if (req.headers.cookie === undefined) {
    res.redirect('/');
  } else {
    const [, userid] = req.headers.cookie.split('=');
    const user = userList.filter((v) => v.id === userid);
    if (user.length) {
      res.render('profile.html', { user: user[0] });
    } else {
      res.redirect('/');
    }
  }
});

app.get('/logout', (req, res) => {
  res.setHeader('Set-Cookie', 'login=true; Max-age=0');
  res.redirect('/');
});

app.listen(3000);

혹시몰라 올려보는 전체코드

 

흐음 혼자서 이렇게해도 되지 않을까..? 하면서

내맘대로 만들다 보니,

이런저런 오류들이 많이 생겼었다.

그런데 그런 오류들 덕에 왜 수업중에 교수님이 이렇게 코드를 짰는지도 알수 있게됐다.

 

재밌었다..!

728x90
728x90

댓글