Programming/Node.js

Node.js + express-session 연동 예제 :: 프로젝트 생성부터 로그인 구현하기

고고마코드 2022. 7. 7. 13:58
반응형

Window 10 환경에서 node.js를 사용했습니다.
npm init 부터 로그인 UI까지 만드는 과정을 기록합니다.

편의상 node로 프론트화면까지 구성합니다.
기본적으로 node는 설치가 되어 있다고 생각하고 진행합니다.


1. express-generator로 프로젝트 생성

원하는 경로에 새로운 디렉터리를 만들어요.

저는 node-express-auth 라는 이름으로 디렉터리를 하나 만들었요.

이제 경로 내에 들어가 express-generator로 node 기본 구조를 만들 거예요.

express로 프로젝트 생성

$ express ex-auth -e --git

의존 패키지 설치

$ cd ex-auth
$ npm install
$ npm install bootstrap --save
$ npm install jquery --save

로그인 화면을 조금 더 이쁘게 꾸미기 위해 Bootstrap까지 의존 패키지를 설치했어요.

express-generator로 프로젝트 구성하는 방법이나 자세한 설명은 아래 글을 참고하세요.

Node.js :: express-generator 로 개발환경 세팅


2. 프로젝트 실행

프로젝트 실행 (기본)

$ npm start

pm2가 설치되어 있지 않으신 분은 기본으로 실행하시면 되고,

프로젝트 실행 (pm2)

$ pm2 start bin/www --name "ex-auth" --watch

pm2가 설치되어 있으시면 pm2로 실행하시면 됩니다.

pm2 설치 및 사용 방법이 궁금하시면 아래 글을 참고해 주세요.

Node.js :: PM2 기본 간단 정리


3. 라우트 설정

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

...

app.use('/', indexRouter);
app.use('/users', usersRouter);

라우터가 2개 있어요.

어차피 연습이니까 기본 구조를 최대한 그대로 사용할 생각입니다.

indexRouter에는 login 페이지로 이동할 수 있는 부분을 추가할 것이고

userRouter에는 login 화면 및 실제 처리작업을 추가할 것입니다.


4. 로그인 페이지 생성

로그인 페이지로 이동시키는 화면 만들기

<!DOCTYPE html>
<html>

<head>
  <title>
    <%= title %>
  </title>
</head>

<body>
  <h2>이곳은 index 페이지입니다.</h2>

  <a href="/users">로그인 페이지로 이동</a>
</body>

</html>

index.ejs에 로그인 페이지로 이동할 수 있도록 코드를 수정합니다.

로그인 페이지 생성

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.render('users/login', { title: 'Express - Login' });
});

module.exports = router;

login.ejs를 바라볼 수 있도록 수정합니다.

수정했으니 login.ejs를 만들어야겠죠?

<!DOCTYPE html>
<html>

<head>
  <title>
    <%= title %>
  </title>
  <link rel="stylesheet" href="/bootstrap.min.css" id="bootstrap-css">
  <link rel='stylesheet' href='/stylesheets/style.css' />

  <script src="/jquery.min.js"></script>
  <script src="/bootstrap.min.js"></script>
</head>

<body>
  <form name="loginfrm" action="/users/login_process" method="post">
    <div class="form-group">
      <label for="email">이메일</label>
      <input type="email" class="form-control" id="email" name="email" aria-describedby="emailHelp" placeholder="이메일을 입력하세요." required>
    </div>
    <div class="form-group">
      <label for="password">비밀번호</label>
      <input type="password" class="form-control" id="password" name="password" placeholder="비밀번호를 입력하세요." required>
    </div>
    <button type="submit" class="btn btn-primary">로그인</button>
  </form>
</body>

</html>

Bootstrap과 Jquery를 npm으로 설치하지 않았다면 각각 CDN사용법으로 호출하시면 됩니다.

그러나 npm으로 설치했다면 오류가 발생할 거예요.

각각의 경로를 잡아주지 않아서 발생한 오류입니다.

그리고 form 부분이 중요한데요,

<form name="loginfrm" action="/users/login_process" method="post">

action에는 이동하고자 하는 routing된 경로를 입력해야 하고

우리는 처리페이지를 만드는 것이기 때문에 method에는 post로 입력해야 해요.

Bootstrap, Jquery 경로 설정

...
app.use(express.static(path.join(__dirname, 'public')));

// Bootstrap, Jquery 경로
app.use(express.static(__dirname + '/node_modules/jquery/dist')); 
app.use(express.static(__dirname + '/node_modules/bootstrap/dist/css')); 
app.use(express.static(__dirname + '/node_modules/bootstrap/dist/js'));

app.use('/', indexRouter);
app.use('/users', usersRouter);
...

여기까지 했다면 이제 로그인 페이지를 확인할 수 있습니다.

  • localhost:3000/users

5. 로그인 처리

우선 user.js에 로그인 처리하는 부분을 추가할 건데요.

하나하나 짚어보면서 할게요.

express-session 패키지 설치

$ npm install express-session

먼저 express-session을 설치해 주세요.

var express = require('express');
var session = require('express-session')

app.use(session({
  secret: 'session-secret123!@#',
  resave: false,
  saveUninitialized: false,
}));

app.js 파일 내에서 기존 express 객체가 초기화된 곳 아래에 session을 추가해 주세요.

그리고 서비스에 session 객체를 연결합니다.

  • secret
    session에 사용할 암호입니다. 해당 암호는 절대 외부에 공개되어서는 안 되며, 어차피 별도로 사용할 일도 없으니 예측이 전혀 불가능한 암호로 하는 것이 좋습니다.
    지금은 편의상 app.js 소스 내에 바로 적었지만, 따로 config 파일같은 곳에 변수로 저장해 사용하는 것이 맞습니다.

  • resave
    true일 경우 클라이언트 요청 시 기존에 있던 session에 변경사항이 없을 경우에도 해당 session을 다시 저장한다.
    false일 경우 클라이언트 요청 시 기존에 있던 session에 변경사항이 없으면 해당 session은 그대로 둔다.
    기본값은 true입니다.

  • saveUninitialized
    true일 경우 요청 시 session에 저장할 내용이 없더라도 session을 저장한다.
    false일 경우 요청 시 session에 저장할 내용이 없으면 session을 저장하지 않는다.
    즉, session을 수정하면 저장되고, session을 수정하지 않으면 저장하지 않는다.
    공식적으로는 false로 사용할 것을 권유하고 있습니다. 서버의 저장공간도 아낄 수 있습니다.
    아마 클라이언트의 서버 접근 횟수를 추적하는 목적으로 true를 사용할 수도 있겠네요.
    기본값은 true입니다.

로그인 처리 페이지

router.post('/login_process', (req, res, next) => {
  let post = req.body;
  console.log(post);
  res.send('res login_process');
});

req.body를 사용하면 post로 받은 데이터를 사용할 수 있어요.

console.log를 찍어놓고, 로그인 페이지에서 이메일과 패스워드 입력 후 로그인 버튼을 눌러보세요~

실행중인 서비스에 로그를 보면 console이 찍힌 것을 확인할 수 있습니다.

  • login_process로 이동된 후 consolg.log 결과

req.body.email, req.body.password 이런 식으로 파라미터들을 가져올 수 있어요.

그럼 데이터가 잘 넘어오는 것을 확인했으니 본격적으로 session을 활용해 로그인 처리하는 부분을 만들어 볼게요.

💣 반드시 express-session 관련 내용을 거친 후에 이곳을 봐주세요!

router.post('/login_process', (req, res, next) => {
  let post = req.body;

  let email = post.email;
  let password = post.password;

  req.session.is_logined = true;
  req.session.ss_email = email;

  console.log(req.session);
  res.send('res login_process');
});

준비된 session을 활용할 거예요.

다시 로그인 화면으로 이동 후 이메일과 비밀번호를 입력하고 로그인을 눌러보세요.

  • login_process로 이동된 후 consolg.log 결과

console을 확인하면 Session을 확인할 수 있어요.

나머지 옵션은 별도로 주지 않았기에 기본으로 설정된 값으로 되어 있으며,

is_logined랑, ss_email이 세션에 등록된 것을 볼 수 있어요.

세션이 정상적으로 등록되는 것을 확인했으니 이제 로그인 완료 시키면서 index 페이지로 보낼게요.

router.post('/login_process', (req, res, next) => {
  let post = req.body;

  let email = post.email;
  let password = post.password;

  req.session.is_logined = true;
  req.session.ss_email = email;

  req.session.save(function () {
    res.redirect(`/`);
  });
});
  • localhost:3000

로그인은 되었고, index페이지로 이동했지만 index페이지에 로그인 체크를 하지 않았으니, 이제 로그인 여부에 따라 구분하는 코드를 삽입할게요.


6. 로그인 체크

router.get('/', function(req, res, next) {
  // res.render('index', { title: 'Express' });

  let is_logined = req.session.is_logined;
  let ss_email = req.session.ss_email;
  res.render('index', {
    title: 'Express',
    is_logined: is_logined,
    ss_email: ss_email
  })
});

session의 값을 가져와 로그인 여부랑 누가 로그인 했는지를 가져왔어요.

근데 귀찮아서 이렇게 하기는 했는데, 이 소스를 모든 곳에 다 추가할 수는 없잖아요.

그래서 별도의 공통함수를 만드는 것이 좋아요.

만드는 김에 UI까지 만들어서 출력하는 걸로 하죠!

보통 로그인/로그아웃 UI는 공통으로 쓰니까요~

루트경로 아래네 lib/login.js 를 새로 만들게요.

module.exports = {
    isLogin:function(req, res) {
        return req.session.is_logined;
    },
    loginStatusUI:function(req, res) {
        let loginStatusUI = '<a href="/users">login</a>';
        if (this.isLogin(req, res)) {
            loginStatusUI = `<b>${req.session.ss_email}</b>님 안녕하세요. | <a href="/users/logout_process">logout</a>`;
        }
        return loginStatusUI;
    }
}
  • isLogin
    로그인 체크 여부를 판단

  • loginStatusUI
    로그인 체크 여부에 따라 UI구현

router.get('/', function(req, res, next) {
  // res.render('index', { title: 'Express' });

  res.render('index', {
    title: 'Express',
    loginStatusUI: login.loginStatusUI(req, res),
  })
});

index.js를 다시 수정했어요.

물론 나중에는 로그인UI 부분을 별도로 관리해야겠지만 편의상 일단은 이렇게 사용할게요.

이제 테스트를 해볼까요?

  • localhost:3000 (로그인 전)

  • localhost:3000/users

  • localhost:3000 (로그인 후)


7. 로그아웃

loginStatusUI 내에서 /users/logout_process 경로로 이동하면 로그아웃 되도록 UI를 만들었어요.

이제 logout_process 처리하는 부분을 만들거예요.

router.get('/logout_process', (req, res, next) => {
  req.session.destroy(function(err){
    res.redirect('/');
  });
});

session을 제거해버리면 됩니다.

로그아웃 처리까지 완료했습니다.


8. 세션 저장하기

아마 지금까지 수정하면서 서버가 리로드되면 계속 세션이 끊겼을 거예요.

express-session은 기본적으로 메모리 저장소에 세션을 보관해요.

즉, 서버 또는 클라이언트가 끊기면 세션도 끊긴다는 말입니다.

그럼 매번 접속할 때마다 로그인 해야 돼요ㅜㅜ

세션이 끊기는 걸 방지하기 위해서는 서버측에 세션을 물리적으로 저장해야 해요.

session-file-store라고 세션을 파일로 저장하는 방법이 있습니다.

여기서는 session-file-store만 소개할 거고 express-mysql-session을 사용할 수도 있는데 이 부분은 다음 글에서 소개하도록 할게요.

session-file-store 패키지 설치

$ npm install session-file-store
var session = require('express-session')
var FileStore = require('session-file-store')(session)

...

app.use(session({
  secret: 'session-secret123!@#',
  resave: false,
  saveUninitialized: false,
  store:new FileStore(),
}));

상단에 FileStore 모듈을 불러오는 부분을 추가합니다.

그 후 아까 session 지정했던 부분에 store 옵션을 추가해요.

그러고 다시 서버를 재시작하면 루트경로에 sessions라는 디렉터리가 생겼을 거예요.

물론 아직 아무것도 없을 거예요.

이제 아까처럼 로그인을 한 번 해볼까요?

  • 로그인 후 session 물리적 저장소

이제 서버를 껐다켜보세요. 더 이상 로그아웃이 되지 않죠?

세션 설정 시 쿠키의 다양한 옵션들도 줄 수 있지만 나중에 별도의 글로 작성할게요.

다음 글은 db를 연동하여 로그인 정보 및 session을 db에 저장하도록 할게요.


9. 전체 소스 코드

https://github.com/gogoma-code/node-express-auth.git (branch::ex-auth)


참고자료

  1. session + auth

  2. express-session

  3. session-store


반응형