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분
}
);
payload에 "iat": 1671446625는 자동으로 들어가는 생성 시간이다.
JWT 토큰 복호화
📄 app.js
const decodeToken = jwt.decode(token); // jwt의 payload 확인하기 위해 사용
console.log(decodeToken);
JWT 토큰 유효성 검사
- 암호화를 할 때 사용한 비밀키가 일치하는지 검증
- 해당하는 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
📌 오픈 라이브러리 설치
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
📌 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 |