본문 바로가기

JavaScript

Node.js 숙련 1주차_2

728x90

Node.js 숙련 1주차_2


📌 쿠키(Cookie)

브라우저가 서버로부터 응답으로 Set-Cookie 헤더를 받은 경우, 해당 데이터를 저장한 뒤 모든 요청에 포함하여 보냄

보안에 취약

 

📌 세션(Session)

데이터를 서버에서만 저장(Stateful)하기 때문에 보안이 좋음

사용자가 많은 경우 서버에 저장해야 할 데이터가 많아서 서버가 터질 수 있음

 

 

📌 JWT

header.payload.signature

 

  • header(머리) : signature에서 어떤 암호화를 사용하여 생성된 데이터인지 표현
  • payload(가슴) : 개발자가 원하는 데이터를 저장
  • signature(배) : 토큰이 변조되지 않은 정상적인 토큰인지 확인할 수 있게 도와줌(특정 키)

 

JWT는 누구나 복호화(Decode) 가능하므로 payload에는 민감한 정보(개인정보, 비밀번호) 는 담지 않도록 해야 한다.

 

데이터를 교환하고 관리하는 방식인 쿠키/세션과 달리, JWT는 단순히 데이터를 표현하는 형식임.

 

JWT로 만든 데이터를 브라우저로 보내도 쿠키처럼 자동으로 저장되지는 않지만, 변조가 거의 불가능하고 서버에 데이터를 저장하지 않기 때문에 서버를 Stateless(무상태)로 관리할 수 있기 때문에 최근 많이 쓰이는 기술중 하나입니다.

 

서버가 죽었다가 살아나도 똑같은 동작을 하는 것을 Statelsee라고 함.


JWT 실습

 

📌 오픈 라이브러리 설치

npm init -y
npm i jsonwebtoken -S

 


JWT 토큰 생성

 

📄 app.js

const token = jwt.sign(
    { myPayloadData: 1234 }, // jwt를 이용해서 payload 설정하는 부분 
    "mysecretkey", // jwt를 이용해서 암호화를 하기 위한 비밀키
    {
        expiresIn: new Date().getMinutes() + 1 // 만료시간 1분
    }
    );

 

jwt.io

payload에 "iat": 1671446625는 자동으로 들어가는 생성 시간이다.


JWT 토큰 복호화

 

📄 app.js

const decodeToken = jwt.decode(token); // jwt의 payload 확인하기 위해 사용
console.log(decodeToken);

JWT 토큰 유효성 검사

 

  1. 암호화를 할 때 사용한 비밀키가 일치하는지 검증
  2. 해당하는 jwt가 만료되었는지 검증

 

📄 app.js

const verifyToken = jwt.verify(token, "mysecretkey");
console.log(verifyToken);

 

 

📌 git repo

godee95/node_prac_jwt: node jwt (github.com)

 

GitHub - godee95/node_prac_jwt: node jwt

node jwt. Contribute to godee95/node_prac_jwt development by creating an account on GitHub.

github.com


📌 Access Token

사용자의 권환이 확인(로그인) 되었을 경우, 해당 사용자를 인증하는 용도로 발급

 

📌 Refresh Token

해당하는 사용자의 모든 인증 정보를 관리하는 것이 아니라,

특정한 사용자가 Access Token을 발급받을 수 있게 하기 위한 용도로만 사용됨.

OTP와 같이 짧은 시간 내에서만 인증 정보를 확인할 수 있게 하고, 토큰이 유출되더라도 피해를 최소화 할 수 있기 때문

 

 


Refresh Token 실습

 

📌 API

Refresh Token API

 

 

 

📌 오픈 라이브러리 설치

npm init -y
npm install express jsonwebtoken cookie-parser -S

 

 

📄 app.js

// app.js

const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
const express = require("express");
const app = express();
const port = 3002;
const SECRET_KEY = `HangHae99`;

app.use(cookieParser());

let tokenObject = {}; // Refresh Token을 저장할 Object

app.get("/set-token/:id", (req, res) => {
  const id = req.params.id;
  const accessToken = createAccessToken(id);
  const refreshToken = createRefreshToken();

  tokenObject[refreshToken] = id; // Refresh Token을 가지고 해당 유저의 정보를 서버에 저장합니다.
  res.cookie('accessToken', accessToken); // Access Token을 Cookie에 전달한다.
  res.cookie('refreshToken', refreshToken); // Refresh Token을 Cookie에 전달한다.

  return res.status(200).send({ "message": "Token이 정상적으로 발급되었습니다." });
})

// Access Token을 생성합니다.
function createAccessToken(id) {
  const accessToken = jwt.sign(
    { id: id }, // JWT 데이터
    SECRET_KEY, // 비밀키
    { expiresIn: '10s' }) // Access Token이 10초 뒤에 만료되도록 설정합니다.

  return accessToken;
}

// Refresh Token을 생성합니다.
function createRefreshToken() {
  const refreshToken = jwt.sign(
    {}, // JWT 데이터
    SECRET_KEY, // 비밀키
    { expiresIn: '7d' }) // Refresh Token이 7일 뒤에 만료되도록 설정합니다.

  return refreshToken;
}



app.get("/get-token", (req, res) => {
  const accessToken = req.cookies.accessToken;
  const refreshToken = req.cookies.refreshToken;

  if (!refreshToken) return res.status(400).json({ "message": "Refresh Token이 존재하지 않습니다." });
  if (!accessToken) return res.status(400).json({ "message": "Access Token이 존재하지 않습니다." });

  const isAccessTokenValidate = validateAccessToken(accessToken);
  const isRefreshTokenValidate = validateRefreshToken(refreshToken);

  if (!isRefreshTokenValidate) return res.status(419).json({ "message": "Refresh Token이 만료되었습니다." });


  if (!isAccessTokenValidate) {
    const accessTokenId = tokenObject[refreshToken];
    if (!accessTokenId) return res.status(419).json({ "message": "Refresh Token의 정보가 서버에 존재하지 않습니다." });

    const newAccessToken = createAccessToken(accessTokenId);
    res.cookie('accessToken', newAccessToken);
    return res.json({ "message": "Access Token을 새롭게 발급하였습니다." });
  }

  const { id } = getAccessTokenPayload(accessToken);
	return res.json({ "message": `${id}의 Payload를 가진 Token이 성공적으로 인증되었습니다.` });
})


// Access Token을 검증합니다.
function validateAccessToken(accessToken) {
  try {
    jwt.verify(accessToken, SECRET_KEY); // JWT를 검증합니다.
    return true;
  } catch (error) {
    return false;
  }
}

// Refresh Token을 검증합니다.
function validateRefreshToken(refreshToken) {
  try {
    jwt.verify(refreshToken, SECRET_KEY); // JWT를 검증합니다.
    return true;
  } catch (error) {
    return false;
  }
}

// Access Token의 Payload를 가져옵니다.
function getAccessTokenPayload(accessToken) {
  try {
    const payload = jwt.verify(accessToken, SECRET_KEY); // JWT에서 Payload를 가져옵니다.
    return payload;
  } catch (error) {
    return null;
  }
}

app.get("/", (req, res) => {
  res.status(200).send("Hello Token!");
})

app.listen(port, () => {
  console.log(port, '포트로 서버가 열렸어요!');
})

 

📌 set-token

쿠키 발급
발급받은 쿠키 2개

 

📌 get-token

get token

 

📌 git repo

godee95/node-access-refresh-token: node-access-refresh-token (github.com)

 

GitHub - godee95/node-access-refresh-token: node-access-refresh-token

node-access-refresh-token. Contribute to godee95/node-access-refresh-token development by creating an account on GitHub.

github.com

 

'JavaScript' 카테고리의 다른 글

Node.js 숙련 1주차_4  (0) 2022.12.20
Node.js 숙련 1주차_3  (0) 2022.12.20
Node.js 숙련 1주차_1  (0) 2022.12.19
Node.js 입문 1주차, 개인과제  (0) 2022.12.16
Node.js 입문 주차 1주차_5  (0) 2022.12.14