본문 바로가기
경일/nodejs

[nodejs] express-session 이용해서 로그인 기능 구현

by dev_kong 2022. 2. 9.
728x90
728x90

0. 목차

1. 개요

2. 기본세팅 및 임시데이터 생성

3. 라우터 나누기

4. 미들웨어 나누기

5. ?? 이젠 HTML도 쪼갠다고?

6. 기능구현

1. 개요

2022.02.09 - [경일/nodejs] - [nodejs] express-session 사용하기

 

[nodejs] express-session 사용하기

0. 목차 1. 개요 2. 기본 세팅 3. express-session / MemoryStore 설치 및 적용 1. 개요 2022.02.09 - [경일/nodejs] - [nodejs] 세션으로 구현한 로그인 기능 라우팅 [nodejs] 세션으로 구현한 로그인 기능 라우..

kong-dev.tistory.com

이전 포스팅에서 다룬 express-session 이용해서 로그인 기능 구현해볼거임

사용될 라이브러리는 

express, express-session, memorystore, nunjucks 이다.

2. 기본세팅 및 임시데이터 생성

사용할 라이브러리 모두 땡겨오고,

세션 생성 까지해보겠다.

 

const express = require('express');
const nunjucks = require('nunjucks');
const session = require('express-session');
const MemoryStore = require('memorystore')(session);

const app = express();

const maxAge = 1000 * 60 * 5;

const sessionObj = {
  secret: 'kong',
  resave: false,
  saveUninitialized: true,
  store: new MemoryStore({ checkPeriod: maxAge }),
  cookie: {
    maxAge,
  },
};

app.use(session(sessionObj));

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

app.use(express.urlencoded('views',{ extended: ture }));

app.get('/', (req, res) => {
  res.send('hello server');
});

app.listen(3000);

뚝 - 딱

 

이제 임시데이터(user 정보) 를 model 디렉토리에 만들고,

땡겨올거임 

const userList = [
  {
    id: 'kong1234',
    pw: '1234',
    name: 'kong',
  },
  {
    id: 'pea1234',
    pw: '5678',
    name: 'pea',
  },
  {
    id: 'peanut1234',
    pw: '7890',
    name: 'peanut',
  },
];

module.exports = userList;

 

const userList = require('./model/user.js');

이렇게 해주면 된다.

3. 라우터 나누기

수업에선 먼저 server.js 에 모든 라우터를 다 만든 다음에

파일을 쪼갰는데,

나는 오히려 그게 더 복잡한거 같아서

처음부터 나누고 시작해보려고 한다.

 

라우터 쪼개기는

2022.02.08 - [경일/nodejs] - [nodejs] express 라우터기능/ 미들웨어 나누기로 파일 쪼개기

 

[nodejs] express 라우터기능/ 미들웨어 나누기로 파일 쪼개기

0. 목차 1. 개요 2. 라우터 쪼개기 3. 미들웨어 쪼개기 1. 개요 라우터가 뭘까? 이제껏 만들었던 server.js 들에 만들었던 app.get 또는 app.post 같은 애들을 전부 라우터라고 한다. https://kong-dev.tistory.co..

kong-dev.tistory.com

여기 있다.

 

user.js -> index.js -> server.js

로 만들어 보려고 한다.

 

이 쯤 되니까 코드를 올리기보단 파일 경로를 올리는게 나을것 같다.

 

대충 파일 구성은 이렇게 되있고,

user.js 의 내용을 

export 하고 index에서 require 해준 다음에

index.js 의 내용을 export 하고,

server.js 에서 require 해주었다.

4. 미들웨어 나누기

이젠 미들웨어도 쪼개보자.

이렇게 쪼개 놓은 뒤에, 

미들웨어를 모아놓은 파일에서만 기능개발을 해주면 된다.

굳굳

 

요렇게 index.js  쪼개 주면 된다.

5. ?? 이젠 HTML도 쪼갠다고?

.....ㅎㅎㅎㅎㅎ 이제 하다하다 HTML도 쪼갠다.

nunjucs의 기능을 이용하면 HTML 도 쪼갤 수 있다.

 

빨리 기능개발 하고싶다...

 

왼쪽은 index.html, 오른쪽은 login.html 이다.

보며는 겹치는 코드가 많다.

개발자 특) 코드 겹치는 꼬라지 못봄.

 

여기서 겹치는 코드는 index.html 의 주요 컨텐츠가 되는 로그인 버튼 과

login.html 의 주요 컨텐츠가 되는 id pw 입력창이다.

이거빼곤 다겹침

 

그러니까 겹치는 부분을 다 쪼갤거다.....

우선 views 폴더안에 _layout.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>
    <div id="wrap">
        {% block content %}
        <!--  -->
        {% endblock %}
    </div>
  </body>
</html>

 

그리고 index.html 을 아래와 같이 수정해준다.

{% extends "./_layout.html" %}
<!--  -->
{% block content%}
<h1><a href="/">LOGO</a></h1>
<ul>
  <li><a href="/user/login">로그인</a></li>
</ul>
{% endblock %}

이게 뭔가 싶다.

 

이렇게 해주면 index.html 의 파일을 render 할때

_layout.html 의 내용을 보여준다.

근데!

index.html 에서 block 안의 있는 내용을

_layout.html의 block 안에 담아서 보여준다!

 

그리고 마지막으로 헤더 부분을 처리해주면되는데,

 

헤더부분을 _header.html 이라는 파일에 따로 작성해주고,

views 안에 template 이라는 디렉토리안에서 관리해줄 거다.

 

그리고 index에서 로고부분 지우고

_layout.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>
    <div id="wrap">
      {% include "./template/_header.html" %}
      <!--  -->
      {% block content %}
      <!--  -->
      {% endblock %}
    </div>
  </body>
</html>

include 의 역활을 경로에 해당하는 파일의 내용을 포함에서 보여주는 역활을 한다.

extends 와 비슷한거 같기도 하지만,

정반대의 역활을 한다.

 

이렇게 login 페이지도 구성을 해보자.

{% extends "../_layout.html" %}
<!--  -->
{% block content %}
<form action="/user/login" method="POST">
  <ul>
    <li>id : <input type="text" name="userid" /></li>
    <li>pw : <input type="text" name="userpw" /></li>
    <button type="submit">로그인</button>
  </ul>
</form>
{% endblock %}

요렇게 작성해주면 된다.

실제로 서버를 돌려보면 매우 아주 잘 동작하는걸 볼 수 있다.

 

그리고 현재 디렉토리 구성이다.. ㅎ

그래.. 코드가 복잡한거보단 디렉토리가 복잡한게 낫지... 암암...

암걸릴거같다.

6. 기능구현

드디어..!

드디어 기능 구현이다..ㅜㅜㅠㅠㅜ

로그인 부터 하나하나 해보자

사실 기능개발은

2022.02.09 - [경일/nodejs] - [nodejs] 세션으로 구현한 로그인 기능 라우팅

 

[nodejs] 세션으로 구현한 로그인 기능 라우팅

0. 목차 1. 개요 2. express 라우터로 나누기 3. 미들웨어 나누기 1. 개요 2022.02.08 - [경일/nodejs] - [nodejs] 세션 이용해서 로그인기능 만들기 [nodejs] 세션 이용해서 로그인기능 만들기 0. 목차 1. 개요 2..

kong-dev.tistory.com

얘랑 거의 비슷하다 그러니까 빠르게 후다닥

6-1. login POST

모든 기능개발은 ~.controller.js 파일에서 해주면 된다.

그런데 user정보가 server.js dp 있다.

후다닥 가서 user.controller.js 에 가져다주자.

 

exports.loginPostMid = (req, res) => {
  const { userid, userpw } = req.body;
  const [user] = userList.filter((v) => v.id === userid && v.pw === userpw);

  if (user !== undefined) {
    console.log('login');
    res.redirect('/');
  } else {
    console.log('login fail');
    res.redirect('/');
  }
};

우선 이렇게 해준뒤에,

이제 세션에 user 정보를 추가해줘야한다.

세션은 req.session 으로 접근 할 수 있다.

 

exports.loginPostMid = (req, res) => {
  const { userid, userpw } = req.body;
  const [user] = userList.filter((v) => v.id === userid && v.pw === userpw);

  if (user !== undefined) {
    req.session.user = user;
    console.log(req.session);
    res.redirect('/');
  } else {
    console.log('login fail');
    res.redirect('/');
  }
};

이렇게 세션에 추가를 해주고 

session 을 출력해보면

 

요렇게 user 가 추가된걸 볼수 있다.

 

이제 로그인에 실패했을 때는 알림을 띄어주고

서버를 되돌아가면 된다.

이기능은 저번과는 다른 방식으로 해보려고한다.

 

res.send() 를통해

script 태그를 전달해서

script 태그 내의 자바스크립트 코드가 실행되게 끔 할거다.

 

else {
    res.send(`
      <script>
        alert('등록되지 않은 회원입니다.')
        location.href = '/'
      </script>`);
  }

 

요렇게 해주면 된다!

location.href 는 페이지를 이동하게 해주는 코드이다.

근데 이거 뭔가 많이 쓸거 같다.

어떤 작업을 했을때 alert를 띄어주고,

페이지를 이동하는거 

이런식으로 자주 사용되는거는 함수로 만들두면 재사용성이 높아진다.

그리고 이런식으로 만들어진 함수들은 util이란 폴더안에 util.js 안에서 관리하고,

모듈로 땡겨와서 사용하면 좋을 것같다.

exports.alertMove = (path, msg) => {
  return ` <script>
        alert('${msg}')
        location.href = '${path}'
      </script>`;
};

이렇게해주고

 

exports.loginPostMid = (req, res) => {
  const { userid, userpw } = req.body;
  const [user] = userList.filter((v) => v.id === userid && v.pw === userpw);

  if (user !== undefined) {
    req.session.user = user;
    console.log(req.session);
    res.redirect('/');
  } else {
    res.send(utill.alertMove('/','등록되지 않은 회원입니다'));
  }
};

 

이렇게 해주면 된다.

 

마지막으로 로그인이 됐을 때 안됐을 때 화면 구성 달라지게 해주는 작업을 하자.

 

로그인 되면 session 에 user 라는 이름의 객체가 추가된다.

 

그럼 메인 페이지에서 로그인이 됐는지 안됐는지 확인 할 수 있는 방법은

session 에 user 라는 객체가 들어있는지 아닌지 확인 해주면 될것 같다!

 

exports.indexGetMid = (req, res) => {
  const user = req.session.user;

  if (user !== undefined) {
    res.render('index.html', { user });
  } else {
    res.render('index.html');
  }
};

index.js 를 이렇게 수정해주었다.

 

6-2. profile GET

매우 간단하다

접속하면

세션에 있는 user 를

nunjucks 통해서 html 로 전달해주기만 하면된다 ^^

 

exports.profileGetMid = (req, res) => {
  const { user } = req.session;
  res.render('user/profile', { user });
};

이렇게 만들어 주고,

 

{% extends "../_layout.html" %}
<!--  -->
{% block content %}
<ul>
  <li>id : {{user.id}}</li>
  <li>name : {{user.name}}</li>
</ul>
{% endblock %}

profile.html 은 이렇게 짜주면 된다.

 

6-3. logout GET

로그아웃은 겁나 쉽다.

너무나 고마운

node.js 에서 session 을 삭제 하는 경우에는

req.session.detroy(()=>{
	req.session
})

이렇게 해주면 된다.

ㅎ 원리 따윈 모른다.

그냥 된다.

 

exports.logoutGetMid = (req, res) => {
  req.session.destroy(() => {
    req.session;
  });
  res.redirect('/');
};

 

이렇게 해주면 된다.

그러면 세션이 지워지고

메인페이지로 이동한다.

 

세션이 지워진걸 확인하기 위해 req.session 을 출력하는 코드를 넣어봤다.

exports.logoutGetMid = (req, res) => {
  req.session.destroy(() => {
    req.session;
  });
  console.log('req.session : ' + req.session);
  res.redirect('/');
};

 

그리고 실행해보면,

 

session 이 지워졌기 때문에 undefined 가 출력된 모습이다.

 

근데 세션은 지워진거 같은데

쿠키는 남아있다.

쿠키는 안지워줘도 되는건가..?

 

이 상태라도 동작은 잘 되는데 뭔가 좀 찝찝하달까.

내일 물어봐야징

 

다해따!

가 아니라..

하나 남긴했다.

 

어떤 미친사용자가 로그인도 안하고 

주소창을 통해 /user/profile 로 접속하게 되면

 

이런화면이 보여진다.

 

req.session.user 를 확인해보고,

있을때와 없을때 의 케이스를 나눠서 실행되도록 하면 될듯하다.

 

exports.profileGetMid = (req, res) => {
  const { user } = req.session;
  if (user !== undefined) {
    res.render('user/profile', { user });
  } else {
    res.send(utill.alertMove('/', '로그인후 이용가능합니다.'));
  }
};

이렇게

 

로그아웃도 마찬가지로 해주면 될듯하다

 

exports.logoutGetMid = (req, res) => {
  const { user } = req.session;
  if (user !== undefined) {
    req.session.destroy(() => {
      req.session;
    });
    res.redirect('/');
  } else {
    res.send(utill.alertMove('/', '로그인후 이용가능합니다'));
  }
};

이렇게

어.. 근데 이거 코드 겹치는데..?

그럼 미들웨어로 뺄수 있을듯.

 

exports.useMid = (req, res, next) => {
  const { user } = req.session;
  if (user === undefined) {
    res.send(utill.alertMove('/', '로그인 후 이용가능합니다'));
  } else {
    next();
  }
};

exports.profileGetMid = (req, res) => {
  const { user } = req.session;
  res.render('user/profile', { user });
};

exports.logoutGetMid = (req, res) => {
  req.session.destroy(() => {
    req.session;
  });
  res.redirect('/');
};

 

이렇게 빼준다.

로그인이 되어있지 않은 상황이라면,

alertMove 함수가 실행될 것이고,

로그인이 돼있다면,

next() 함수가 실행되면서,

조건에 맞는 다음 라우터를 실행 시킬 것이다.

 

const express = require('express');
const userController = require('./user.controller.js');

const router = express.Router();

router.get('/login', userController.loginGetMid);

router.post('/login', userController.loginPostMid);

router.use('/', userController.useMid);

router.get('/profile', userController.profileGetMid);

router.get('/logout', userController.logoutGetMid);

module.exports = router;

user.js 파일인데,

중요한건 router.use 의 위치다.

만약 저게 최상단에 위치해 있다면..?

 

로그인이 안되어 있어서,

로그인을 하려고 로그인 버튼을 누르면,

로그인 후 이용가능하다 알림이 뜨고 다시 메인페이지로 돌아가게 되는

굉장히 얼척없는 상황이 벌어진다.

 

라우터 역시 위에서 부터 아래로 절차지향적으로 실행 되기 때문에

router.use의 위치를 잘 선정 해줘야 한다.

 

이렇게 해주면 진짜 끝!

728x90
728x90

댓글