본문 바로가기
학원에서 배운 것/node.js

KDT 5th 웹개발자 입문 수업 31일차

by 쿠리의일상 2023. 3. 20.

로그인이 되지 않으면 글수정과 글삭제를 불가능하게 만들기

function isLogin(req, res, next) {
  if (req.session.login === true) {
    next();
  } else {
    res.send(
      '로그인이 필요합니다. <br/><br/> <a href="/login">로그인 페이지로 이동</a>'
    );
  }
}

해당 미들 웨어를 글수정과 글삭제 미들웨어에 넣어줘서 구현해주면 로그인이 되지 않을 때 설정이 가능하다.

 

// 수정 페이지 호출
router.get('/modify/:id', isLogin, (req, res) => {
  boardDB.getArticle(req.params.id, (data) => {
    if (data.length > 0) {
      res.render('db_board_modify', { findArticle: data[0] });
    } else {
      const err = new Error('게시글 찾기 실패');
      err.statusCode = 500;
      throw err;
    }
  });
});

// 글 수정하기
router.post('/modify/:id', isLogin, (req, res) => {
  if (req.body.title && req.body.content) {
    boardDB.modifyArticle(req.params.id, req.body, (data) => {
      if (data.affectedRows >= 1) {
        res.redirect('/dbBoard');
      } else {
        const err = new Error('게시글 수정 실패');
        err.statusCode = 500;
        throw err;
      }
    });
  } else {
    const err = new Error('게시글 요청 실패');
    err.statusCode = 400;
    throw err;
  }
});
// 글 삭제하기
router.delete('/delete/:id', isLogin, (req, res) => {
  boardDB.deleteArticle(req.params.id, (data) => {
    if (data.affectedRows >= 1) {
      res.status(200).send('게시글 삭제 완료');
    } else {
      const err = new Error('게시글 삭제 실패');
      err.statusCode = 500;
      throw err;
    }
  });
});

 

 

쿠키를 사용한 자동 로그인

로그아웃 후 60초 동안은 세션이 없어도 자동 로그인이 되도록 구현 ->

세션은 브라우저를 종료하면 사라지지만 쿠키는 만료일까지 남아있음

즉, 쿠키를 이용하여 구현을 해주면 된다.

 

로그인을 하면 쿠키 발행

  • 사용자 id 정보 -> req.body.id
  • 10초의 expires
  • httpOnly 옵션 사용
  • Signed 옵션을 켜주기

app.use(cookieParser('cookie-password'));

 

      // 로그인 쿠키 발행
        res.cookie('user', req.body.id, {
          maxAge: 1000 * 10,
          httpOnly: true,
          signed: true,
        });

로그인 시 'user' 라는 이름의 쿠키를 발행해줘서 브라우저를 종료하더라도 쿠키에 남은 정보때문에 로그아웃처리 하지 않아도 로그인이 되어 있게 된다.

 

 

세션을 만들 때도 기간을 설정해주지 않아야 브라우저가 종료 됐을 때 세션도 종료된다.

app.use(
  session({
    secret: '1234',
    resave: false,
    saveUninitialized: true,
    // cookie: {
    //   maxAge: 1000 * 60 * 60,
    // },
  })
);

 

// 로그인 확인용 미들웨어
function isLogin(req, res, next) {
  if (req.session.login === true || req.signedCookies.user) {
    next();
  } else {
    res.send(
      '로그인이 필요합니다. <br/><br/> <a href="/login">로그인 페이지로 이동</a>'
    );
  }
}

req.signedCookies.user 로 로그인했던 쿠키를 가져올 수 있다.

 

router.get('/logout', async (req, res) => {
  req.session.destroy((err) => {
    if (err) throw err;
    res.clearCookie('user');
    res.redirect('/');
  });
});

로그아웃 시 clearCookie 로 쿠키를 없애줄 필요가 있다.

 

 

쿠키와 세션

HTTP 프로토콜은 stateless(통신이 끝나면 상태를 유지하지 않는 특징) 한 특성을 가지므로 서버는 클라이언트가 누구인지 매번 확인할 필요가 있다. 하지만 클라이언트에서 계속 확인을 해주면 매우 귀찮아지므로 쿠키와 세션을 사용하여 이를 보완한다.

즉 쿠키와 세션을 사용했을 경우 로그인을 1번 해주면 사용자에 대한 인증을 유지하게 된다.

 

또한 HTTP 프로토콜은 클라이언트가 요청을 한 후 응답을 받으면 그 연결을 끊어버리는 특징이 있어서

HTTP 는 먼저 클라이언트가 request 를 서버에 보내면 서버는 클라이언트에게 요청에 맞는 response를 보내고 접속을 끊어버린다.

 

쿠키

쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 데이터 파일

사용자 인증이 유효한 시간을 명시할 수 있으며 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지된다.

쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조한다.

 

쿠키 하나는 4kb까지 저장할 수 있으며 클라이언트 300개까지 쿠키를 저장할 수 있다.

방문 사이트에 로그인 시, 아이디와 비밀번호를 저장하는거나 쇼핑몰의 장바구니 기능, 자동 로그인, 팝업에서 오늘 더이상 이 창을 보지 않음을 체크 등에 사용

 

쿠키의 구성 요소에는

  • 쿠키 이름
  • 쿠키값
  • 유효시간
  • 도메인
  • 경로

 

쿠키의 동작 방식

1. 클라이언트가 페이지를 요청

2. 서버에서 쿠키를 생성

3. HTTP 헤더에 쿠키를 포함시켜 응답

4. 브라우저가 종료되어도 쿠키 만료 기간이 있다면 클라이언트에서 보관

5. 같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보냄

6. 서버에서 쿠키를 읽어들여 이전 상태 정보를 변경할 필요가 있다면 쿠키를 업데이트하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답한다.

 

세션

쿠키를 기반하고 있지만 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버측에서 관리

서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하여 웹 브라우저가 서버에 접속하여 브라우저를 종료할 때까지 인증상태를 유지한다.

사용자에 대한 정보를 서버에 두므로 쿠키보다 보안에 좋지만 사용자가 많아질수록 서버 메모리를 많이 차지 -> 동접자 수가 많은 웹사이트인 경우 서버에 과부하를 주므로 성능 저하의 요인이 됨

클라이언트가 request를 보내면 해당 서버의 엔진이 클라이언트에게 유일한 ID를 부여 -> 세션ID

 

세션 동작 방식

1. 클라이언트가 서버에 접속 시 세션 ID를 발급 받음

2. 클라이언트는 세션 ID에 대해 쿠키를 사용하여 저장하여 가지고 있음

3. 클라이언트는 서버에 요청할 때 쿠키의 세션ID를 같이 서버에 전달하여 요청

4. 서버는 세션 ID를 전달 받아서 별다른 작업없이 세션ID로 세션에 있는 클라잉너트 정보를 가져와서 사용

5. 클라이언트 정보를 가지고 서버 요청을 처리하여 클라이언트에게 응답

 

쿠키를 사용하는 이유

세션은 서버의 자원을 사용하므로 서버의 메모리가 감당할 수 없어질 수 있으며 속도가 느려질 수 있기에 쿠키를 사용해줄 필요가 있음.

쿠키와 세션은 캐시와 다르다.

캐시는 이미지나 css, js 파일 등을 브라우저나 서버 앞 단에 저장해놓고 사용하는 것

한번 캐시에 저장되면 브라우저를 참고하기 때문에 서버에서 변경되어도 사용자는 변경되지 않게 보일 수 있는데 이런 부분을 캐시를 지워주거나 서버에서 클라이언트로 응답을 보낼 때 header 에 캐시 만료시간을 명시하는 방법을 이용

보통 쿠키와 세션의 차이는 저장위치와 보안에 대해 나오는데, 그중에서도 라이프사이클이 제일 중요하다.

 

 

DOTENV

중요 정보-서버 접속 정보 등-를 외부 코드에서 확인이 불가능하도록 도와주고 관리하는 모듈

npm i dotenv 로 설치

require('dotenv').config();

메인 서버에 dotenv를 사용한다고 선언하기 위해서 위처럼 써준다.

 

.env 파일을 최상단 폴더에 만들기

중요한 정보를 해당 파일에 저장

해당 정보가 필요한 곳에서 process.env.저장명 형태로 사용해준다.

해당 파일은 .gitignore 에 추가해줘서 깃 관리에선 벗어나게 해준다.

const mysql = require('mysql');

const connection = mysql.createConnection({
  host: '127.0.0.1',
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  port: '3306',
  database: process.env.DB_DATABASE,
});

connection.connect();

module.exports = connection;

 

 

---- JS

배열 구조 분해 할당

배열의 각 요소를 추출하여 바로 변수로 할당

추출되는 기준은 배열의 순서에 따라 할당된다.

const arr = [1, 2, 3];
// const one = arr[0];
// const twq = arr[1];
// const three = arr[2];
const [one, two, three] = arr;
const today = new Date();
const console.length(today);
const formatedDate = today.toISOStiring().substring(0, 10);
const [ year, month, data] = formatedtDate.split('-');

 

객체 구조 분해 할당

// 객체 구조 분해 할당
const obj = { firstName : '슬기', lastName: '구'};
const { firstName, lastName } = obj;
console.log(obj);

객체의 키를 기준으로 변수에 할당

순서는 무관하나 객체의 키와 이름이 같아야 할당이 가능!

const person = {
  name :'lee',
  address: {
    zipCode : '03068',
    city: 'Seoul',
  },
};

const { address: {city, zipCode} } = person;

console.log(city);
console.log(zipCode);

 

전개 구문

백엔드에서 큰 데이터를 다룰 때 자주 사용

병합, 구조 분해 할당 등에 사용

배열이나 객체 값을 따로 분리하여 흩뿌려준다.

원하는 변수 앞에 ...을 사용

const arr = [1, 2, 3, 4, 5];

console.log(arr); // [1, 2, 3, 4, 5]
console.log(...arr); // 1, 2, 3, 4, 5
const personData = {
  name: '이름',
  age: 29,
};

const personInfo = {
  nickName: '닉네임',
  email: '이메일',
};

const person = {
  personData,
  personInfo,
};
console.log(person);
/*
{
  personData: { name: '이름', age: 29 },
  personInfo: { nickName: '닉네임', email: '이메일' }
}
*/

//////

const person = {
	...personData,
    ...personInfo,
}
/*
{ name: '이름', age: 29, nickName: '닉네임', email: '이메일' }
*/

 

const arr1 = [1, 2, 3];
const arr2 = ['4', '5'];

const arrMerge = [...arr1, ...arr2];
console.log(arrMerge); // [ 1, 2, 3, '4', '5' ]

 

나머지 연산자

const obj = {
  name: '이름',
  gender: 'fm',
  nickname: '닉네임',
};

const { name, ...rest } = obj;
console.log(name, rest);
// 이름 { gender: 'fm', nickname: '닉네임' }

 

const [firstNumber, ...restNumber] = [1, 2, 3, 4, 5];
console.log(firstNumber); // 1
console.log(restNumber); // [2, 3, 4, 5]
function spread(first, ...rest) {
  console.log(first);
  console.log(rest);
}
spread(1, 2, 3, 4, 5);
// 1
// [2, 3, 4, 5]