๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Node.js

Node.js / ์„ธ์…˜(Session)

์„ธ์…˜

์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ƒํƒœ

 

์„ธ์…˜ ๊ธฐ๋ฐ˜ ์ธ์ฆ(Session-based authentication)

์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ƒํƒœ๋ฅผ ์„œ๋ฒ„์— ์ €์žฅํ•ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹

 

์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ์„ ํ•˜๊ฑฐ๋‚˜ ์„œ๋ฒ„์—์„œ ์„ธ์…˜ ์ •๋ณด๋ฅผ ํŒŒ๊ธฐํ–ˆ์„ ๊ฒฝ์šฐ

 

 

 


 

 

 

์‹ค์Šต

์„ธ์…˜ ๊ธฐ๋ฐ˜ ์ธ์ฆ ํ๋ฆ„์„ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด ํ™•์ธํ•ด๋ณด๋Š” ์‹ค์Šต์ด๋‹ค.

์ƒ์„ฑํ•  ํŒŒ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์ƒ์„ฑํ•  ํŒŒ์ผ์€ index.html, style.css, login.js, server.js

 

index.html

๋”๋ณด๊ธฐ
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <h1>๋กœ๊ทธ์ธ ์‹ค์Šต</h1>
    <form>
      <label for="user_id">์•„์ด๋””</label>
      <input autocomplete="false" id="user_id" />
      <label for="user_password">๋น„๋ฐ€๋ฒˆํ˜ธ</label>
      <input id="user_password" type="password" />
      <button id="login_button">๋กœ๊ทธ์ธ</button>
    </form>
    <main>
      <div>์œ ์ € ์ด๋ฆ„ : <span id="user_name"></span></div>
      <div>์œ ์ € ์ •๋ณด : <span id="user_info"></span></div>
      <button id="logout_button">๋กœ๊ทธ์•„์›ƒ</button>
    </main>
    <!-- axios cdn -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="login.js"></script>
  </body>
</html>

 

style.css

๋”๋ณด๊ธฐ
body {
  padding: 0 20px;
}

label {
  display: inline-block;
  width: 80px;
  text-align: center;
}

form {
  display: grid;
  grid-template-columns: auto auto auto;
  grid-template-rows: auto auto;
  gap: 8px;
  justify-content: start;
}

#login_button {
  grid-column: 3 / 4;
  grid-row: 1 / 3;
  width: 80px;
}

main {
  border: 1px solid gray;
  border-radius: 10px;
  padding: 20px;
  margin-top: 20px;
  width: 300px;
  display: none;
}

div {
  margin-bottom: 20px;
}

#logout_button {
  width: 100%;
  height: 50px;
}

 

terminal

npm init -y #์ƒˆ๋กœ์šด package.json ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ, ๋ชจ๋“ˆ ์ดˆ๊ธฐ ์„ธํŒ…
npm i express cors cookie-parser express-session 
#express, cors, cookie-parser, express-session ์„ค์น˜

 

*express-session : express์—์„œ์˜ ์„ธ์…˜ ๊ด€๋ฆฌ์šฉ ๋ฏธ๋“ค์›จ์–ด

 


 

 

์„ธ์…˜์„ ์ฟ ํ‚ค๋กœ ์ €์žฅํ•˜๊ธฐ

 

server.js

const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const session = require('express-session');

const users = [
  {
    user_id: 'test',
    user_password: '1234',
    user_name: 'ํ…Œ์ŠคํŠธ์œ ์ €',
    user_info: '์ €๋Š” ํ…Œ์ŠคํŠธ์œ ์ €์ž…๋‹ˆ๋‹ค...',
  },
];

const app = express();
app.use(
  cors({
    origin: ['http://127.0.0.1:5500', 'http://localhost:5500'],
    methods: ['POST', 'GET', 'DELETE', 'OPTIONS'],
    credentials: true, // ์ฟ ํ‚ค ์ €์žฅ์„ ์œ„ํ•ด ํ•„์š”
  }),
);

app.use(cookieParser());
app.use(express.json());
app.use(
  session({
    // ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด ์„ค์ •ํ•˜๋Š” ๋น„๋ฐ€ ์ฝ”๋“œ
    secret: 'session secret',
    resave: false, // request๊ฐ€ ๋  ๋•Œ๋งˆ๋‹ค ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ญ์ƒ ๋‹ค์‹œ ์ €์žฅํ• ์ง€ ์—ฌ๋ถ€ (๋ณ€๊ฒฝ์ด ์—†์–ด๋„)
    // ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์„ธ์…˜์„ ์ €์žฅํ• ์ง€ ์—ฌ๋ถ€ (์„ธ์…˜์— ์•„๋ฌด ๋‚ด์šฉ์ด ์—†์–ด๋„ ์ €์žฅํ• ์ง€)
    saveUninitialized: false,
    name: 'session_id',
  }),
);

// ๋ Œ๋”๋ง
app.post('/', (req, res) => {
  console.log(req.body);
});

app.listen(3000, () => console.log('์„œ๋ฒ„ ์‹คํ–‰'));

 

 

login.js

// ์—ฌ๊ธฐ์— ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.
const form = document.querySelector('form');
const idInput = document.querySelector('#user_id');
const passwordInput = document.querySelector('#user_password');
const loginBtn = document.querySelector('#login_button');

// ์ฟ ํ‚ค ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ ํ•„์ˆ˜
axios.defaults.withCredentials = true;

// ํผ ์ „์†ก ์‹œ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด์„œ ์„œ๋ฒ„๋กœ ์ „์†ก๋˜๋Š” ๋™์ž‘์„ ๋ง‰๋Š” ์—ญํ• 
form.addEventListener('submit', (e) => e.preventDefault());

function login() {
  const userId = idInput.value;
  const userPassword = passwordInput.value;
  return axios.post('http://localhost:3000', { userId, userPassword });
}

loginBtn.onclick = login;

 

 

์ผ๋‹จ ์ด๋ ‡๊ฒŒํ•˜๋ฉด ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ login.js์—์„œ ์ „์†กํ•œ request์˜ body๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•ด id์™€ password๋ฅผ ์ฝ˜์†”๋กœ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ด์ œ ์ฟ ํ‚ค๋กœ ์ €์žฅํ•˜๋ ค๋ฉด server.js์˜ ๋ Œ๋”๋ง ๋ถ€๋ถ„์— ๋ฐ›์•„์˜จ req.body๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ธ์…˜์„ ์ €์žฅํ•ด ์ „๋‹ฌํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

// ๋ผ์šฐํŒ…
app.post('/', (req, res) => {
  const { userId, userPassword } = req.body;

  // ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ userInfo์— ๋‹ด์Œ
  const userInfo = users.find(
    (el) => el.user_id === userId && el.user_password === userPassword,
  );

  if (!userInfo) {
    res.status(401).send('๋กœ๊ทธ์ธ ์‹คํŒจ');
  } else {
    // ์ฟ ํ‚ค๋ฅผ ๋”ฐ๋กœ ์ „๋‹ฌํ•  ํ•„์š” ์—†์ด express-session์—์„œ ์•Œ์•„์„œ ๋‹ค ํ•ด์คŒ...
    req.session.userId = userInfo.user_id;
    res.send('์„ธ์…˜ ์ƒ์„ฑ ์™„๋ฃŒ');
  }
});

 

์ด์ „์—๋Š” ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ผ ๋•Œ res.cookie('test-cookie', 'my cookie'); ์ด๋Ÿฐ์‹์œผ๋กœ ๋ณด๋‚ด๊ณค ํ–ˆ๋Š”๋ฐ, ์ด๋Š” express-session์—์„œ ๊ธฐ๋ณธ ์„ค์ •์€ ๋‹ค ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ํ•ด์ค„ ํ•„์š”๊ฐ€ ์—†์–ด์กŒ๋‹ค!

 

์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„๋œ ๋ถ€๋ถ„

 

 


 

 

์ฟ ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ

 

๋‚จ์€ ๋ถ€๋ถ„

 

 

login.js

function getUserInfo() {
  return axios.get('http://localhost:3000');
}

loginBtn.onclick = () => {
  login().then(() => getUserInfo());
};

 

์ด์ œ ์ฟ ํ‚ค ์ •๋ณด๋ฅผ ์š”์ฒญํ•ด ์„ธ์…˜ id๋ฅผ ํ™•์ธํ•ด ์ผ์น˜ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›๋„๋ก get ์š”์ฒญ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

 

 

server.js

app.get('/', (req, res) => {
  console.log(req.session);
});

 

์ผ๋‹จ์€ ์ง€๊ธˆ req.session์œผ๋กœ ์„ธ์…˜๊ฐ’์ด ์–ด๋–ป๊ฒŒ ๋“ค์–ด์˜ค๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ฉด

 

 

๋ญ”๊ฐ€ ๊ฐ’์ด ๋“ค์–ด์˜ค๊ณ ๋Š” ์žˆ๋Š”๋ฐ.... ์ •์ž‘ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์€ ์•„์ด๋”” ๊ฐ’์ด ์•ˆ๋ณด์ธ๋‹ค...

์™œ๋ƒํ•˜๋ฉด ์ง€๊ธˆ live server ์ต์Šคํ…์…˜์œผ๋กœ ๊ตฌ๋™์ค‘์ด๋ผ ์ฃผ์†Œ ๊ฐ’์ด http://127.0.0.1:5500/~~์ธ ์ƒํƒœ์ธ๋ฐ,

์ง€๊ธˆ ๋“ค์–ด์˜จ ์ฟ ํ‚ค๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด 

 

 

Domain์ด localhost์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

๋ฌผ๋ก  ์ „ ๊ธ€์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด http://127.0.0.1:5500/~~๋ž‘ http://localhost:5500/ ๋Š” ๊ฒฐ๊ณผ์ ์œผ๋กœ๋Š” ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€๋งŒ,

๋„๋ฉ”์ธ ์ผ์น˜ ๋ฌธ์ œ๋กœ ์ฟ ํ‚ค ๊ณต์œ ๊ฐ€ ์ง€๊ธˆ์ฒ˜๋Ÿผ ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค.

๋•Œ๋ฌธ์— ๊ธฐ์กด ์ฃผ์†Œ์˜ 127.0.0.1์„ localhost๋กœ ๋ฐ”๊ฟ”์„œ ์‹ค์Šตํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.....

 

์ด์ œ ๋„๋ฉ”์ธ๊ณผ ์ฃผ์†Œ๊ฐ€ ์ผ์น˜ํ•˜๊ณ 

 

console.log(req.session)์—์„œ๋„ ์ด์ œ userId๊ฐ’์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

 

 

์ด์ œ ๊ฐ’์ด ์ž˜ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์œผ๋‹ˆ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ๋ฐ›์•„์˜จ ๊ฐ’์„ ๋ Œ๋”๋งํ•˜๋ ค๊ณ ํ•œ๋‹ค.

 

server.js

app.get('/', (req, res) => {
  const userInfo = users.find((el) => el.user_id === req.session.userId);
  return res.json(userInfo);
});

 

 

login.js

// ๊ธฐ์กด html์—์„œ ์•ˆ๊ฐ€์ ธ์˜จ ์š”์†Œ๋“ค์„ ์ถ”๊ฐ€๋กœ ๊ฐ€์ ธ์˜ด
const main = document.querySelector('main')
const userName = document.querySelector('#user_name')
const userInfo = document.querySelector('#user_info')
const logoutButton = document.querySelector('#logout_button')
// ์ƒ๋žต...

// ๋ Œ๋”๋ง ๊ธฐ๋Šฅ 
function renderUserInfo(user) {
  main.style.display = 'block';
  form.style.display = 'none';
  userName.textContent = user.user_name;
  userInfo.textContent = user.user_info;
}

loginBtn.onclick = () => {
  login()
    .then(() => getUserInfo())
    .then((res) => renderUserInfo(res.data));
};

 

์ฃผ์†Œ๋ฅผ localhost๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ฒƒ์„ ์žŠ์ง€๋ง๊ธฐ.......ใ… ใ… ใ…  ๊ทธ๋ž˜์•ผ ๊ฐ’์„ ์ž˜ ๊ฐ€์ ธ์™€์„œ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๋‹ค..

 

 


 

 

๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ

 

server.js

app.delete('/', (req, res) => {
  // ์„ธ์…˜์„ ์ •๋ณด๋ฅผ ์—†์• ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ
  req.session.destroy();
  // ์ฟ ํ‚ค๋„ ์‚ญ์ œํ•ด์ฃผ๊ธฐ
  res.clearCookie('session_id');
  res.send('์„ธ์…˜ ์‚ญ์ œ ์™„๋ฃŒ');
});

 

 

login.js

function logout() {
  return axios.delete('http://localhost:3000');
}

// ๋กœ๊ทธ์•„์›ƒ ํ›„ ๋‹ค์‹œ ์ดˆ๊ธฐ ๋กœ๊ทธ์ธ ํผ์„ ๋„์›Œ์ฃผ๋Š” ํ•จ์ˆ˜
function renderLoginForm() {
  main.style.display = 'none';
  form.style.display = 'grid';
  userName.textContent = '';
  userInfo.textContent = '';
}

logoutBtn.onclick = () => {
  logout().then((res) => {
    console.log(res);
    renderLoginForm();
  });
};

 

'Node.js' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Node.js / ํ† ํฐ(Token)  (0) 2025.05.15
Node.js / ์ฟ ํ‚ค(Cookie)  (0) 2025.05.14
Node.js / ๋„คํŠธ์›Œํฌ ๊ธฐ์ดˆ  (0) 2025.05.12