jwt 토큰 발행, 검증
authorization-demo.js
var jwt = require('jsonwebtoken');
const express = require('express');
const app = express()
const dotenv = require('dotenv')
const path = require('path')
dotenv.config({path: path.join(__dirname, '../.env')})
// 서버 세팅 : 포트 넘버 3000으로 셋팅
app.listen(process.env.PORT, () => {
console.log('Server is running on http://localhost:3000')
})
// GET + "/jwt" : 토큰 발행
app.get('/jwt', (req, res) => {
var token = jwt.sign({foo : 'bar'},process.env.PRIVATE_KEY);
res.cookie("jwt", token, {
httpOnly : true // 자바스크립트로 쿠키에 접근하는 것을 막음 (보안 강화)
})
res.send('토큰 발행 완료!');
});
// GET + "/jwt/decoded" : 토큰 검증
app.get('/jwt/decoded', (req, res) => {
let receivedJwt = req.headers["authorization"];
console.log(receivedJwt);
var decoded = jwt.verify(receivedJwt, process.env.PRIVATE_KEY);
res.send(decoded);
});

/jwt에서 설정한 cookie를 복사해서

/jwt/decoded에서 Authorization에 넣어서 보내면
내용, 발급시간 담긴 jwt받아온 것을 확인할 수 있습니다.
jwt 오류 예외처리

1️⃣ TokenExpiresdError
: 유효기간이 지난 토큰 = 만료된 토큰
2️⃣ JsonWebTokenError
: 문제가 있는 토큰
try...catch
수많은 (개발자가 예상하지 못한) 에러(실수, 사용자 입력을 잘못 한 것, 디비가 응답을 잘못 ..)을 처리하는 문법
try {
// A 코드 실행
} catch (err) {
// 에러 처리
}
let string = '{ "num1":1';
try {
let json = JSON.parse(string);
} catch (err) {
console.log("err.name : " +err.name);
console.log("err.message : " + err.message);
console.log("err : " + err);
}
>>
err.name : SyntaxError
err.message : Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)
err : SyntaxError: Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)
try 구문의 코드를 실행하다가 에러가 발생하면, try코드를 멈추고 -> catch로 err와 함께 바로 빠져나갑니다.
try 구문에서 어떤 에러가 발생해도, if문 분기처리 필요없이 알아서 catch에 잡힙니다.(ex. SyntacError, TypeError)
이 말은, 원래라면 서버가 종료되지만 try catch를 사용하면 서버 종료없이 계속됩니다!
에러 객체
자바스크립트가 고대 개발자들의 노고를 보고 내장 에러 객체를 만들어뒀습니다.
JWT라는 모듈에서 제공하는 에러 객체도 있고, 직접 만들어 쓸 수도 있습니다.
throw 연산자
엘러를 발생시키는 연산자
let error = new Error("대장 에러 객체");
let syntxError = new SyntaxError("구문 에러 객체");
let referenedEror = new ReferenceError("참조 에러 객체");
console.log(error.name);
console.log(error.message);
console.log(syntxError.name);
console.log(syntxError.message);
console.log(referenedEror.name);
console.log(referenedEror.message);
>>
Error
대장 에러 객체
SyntaxError
구문 에러 객체
ReferenceError
참조 에러 객체
그렇다면, 언제 에러를 만들어줘야될까?
let string = '{ "num1":1';
try {
let json = JSON.parse(string);
if(!json.name){
console.log("이름이 없습니다.");
} else {
console.log(json.name); //>> undefined : js입장에선 에러가 아니지만, 우리 입장에선 에러 = 입력값이 잘못된 에러
}
let name = json.name;
console.log(name);
} catch (err) {
console.log("err.name : " +err.name);
console.log("err.message : " + err.message);
console.log("err : " + err);
}
여기서 !json.name이 없을 경우의 오류에는 if문으로 처리했기 때문에 오류가 발생하여도 다음 코드를 실행합니다.
let string = '{ "num1":1';
try {
let json = JSON.parse(string);
if(!json.name){
//console.log("이름이 없습니다.");
throw new SyntaxError("입력 값에 이름이 없습니다.")
} else {
console.log(json.name); //>> undefined : js입장에선 에러가 아니지만, 우리 입장에선 에러 = 입력값이 잘못된 에러
}
let name = json.name;
console.log(name);
} catch (err) {
console.log("err.name : " +err.name);
console.log("err.message : " + err.message);
console.log("err : " + err);
}
if 안에 throw을 넣어주면, 오류를 발생시켜준 것이기 때문에 바로 catch문으로 감
>>
err.name : SyntaxError
err.message : Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)
err : SyntaxError: Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)
admin@kayoungs-MacBook-Pro Devcourse %
BookShop에 적용해보자
좋아요 API
const conn = require('../mariadb'); //db 모듈
const {StatusCodes} = require('http-status-codes'); //status code 모듈
const addLike = (req, res) => {
// 좋아요 추가
const {id} = req.params;
const {user_id} = req.body;
let sql = "INSERT INTO likes(user_id, liked_book_id) VALUES (?, ?);";
let values = [user_id, id];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
const removeLike = (req, res) => {
// 좋아요 삭제
const {id} = req.params;
const {user_id} = req.body;
let sql = "DELETE FROM likes WHERE user_id = ? AND liked_book_id = ?";
let values = [user_id, id];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
module.exports = {
addLike,
removeLike
}
여기서 수정 ==>
const conn = require('../mariadb'); //db 모듈
const {StatusCodes} = require('http-status-codes'); //status code 모듈
const jwt = require('jsonwebtoken'); //jwt 모듈
const dotenv = require('dotenv'); //dotenv 모듈
dotenv.config(); //dotenv 설정
const addLike = (req, res) => {
// 좋아요 추가
const book_id = req.params.id;
//const {user_id} = req.body;
let authorization = ensureAuthorization(req);
let sql = "INSERT INTO likes(user_id, liked_book_id) VALUES (?, ?);";
let values = [authorization.id, book_id];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
function ensureAuthorization(req) {
let receivedJwt = req.headers["authorization"];
console.log(receivedJwt);
let decodedJwt = jwt.verify(receivedJwt, process.env.PRIVATE_KEY);
console.log(decodedJwt);
return decodedJwt;
}
const removeLike = (req, res) => {
// 좋아요 삭제
const book_id = req.params.id;
let authorization = ensureAuthorization(req);
let sql = "DELETE FROM likes WHERE user_id = ? AND liked_book_id = ?";
let values = [authorization.id, book_id];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
module.exports = {
addLike,
removeLike
}
login 했을 때의 Cookie를 복사해
like post때에 Headers에 넣어줍니다.



장바구니



TokenExpriedError 해결하기
기존의 방식으로는 token의
이 만료가 되면 오류가 나고 아예 서버가 종료됩니다.
그렇기 때문에 try catch 문을 넣어주려고 합니다.
const conn = require('../mariadb'); //db 모듈
const {StatusCodes} = require('http-status-codes'); //status code 모듈
const dotenv = require('dotenv'); //dotenv 모듈
dotenv.config(); //dotenv 설정
const jwt = require('jsonwebtoken'); //jwt 모듈
// 장바구니 담기
const addToCart = (req, res) => {
const {book_id, quantity} = req.body;
let authorization = ensureAuthorization(req, res);
let sql = "INSERT INTO cartItems(book_id, quantity, user_id) VALUES(?, ?, ?);";
let values = [book_id, quantity, authorization.id];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
// 장바구니 아이템 목록 조회
const getCartItems = (req, res) => {
const {selected} = req.body; // selected = [1,3]
let authorization = ensureAuthorization(req, res);
if(authorization instanceof jwt.TokenExpiredError) {
return res.status(StatusCodes.UNAUTHORIZED).json({
"message" : "로그인 세션이 만료되었습니다. 다시 로그인 하세요."
});
} else {
let sql = `SELECT cartItems.id, book_id, title, summary, quantity, price
FROM cartItems LEFT JOIN books
ON cartItems.book_id = books.id
WHERE user_id = ? AND cartItems.id IN (?);`;
let values = [authorization.id, selected];
conn.query(sql, values,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
}
// 장바구니 아이템 삭제
const removeCartItem = (req, res) => {
const cartItemId = req.params.id;
let sql = "DELETE FROM cartItems WHERE id = ?;";
conn.query(sql, cartItemId,
(err, results) => {
if(err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(results);
})
}
function ensureAuthorization(req, res) {
try {
let receivedJwt = req.headers["authorization"];
console.log(receivedJwt);
let decodedJwt = jwt.verify(receivedJwt, process.env.PRIVATE_KEY);
console.log(decodedJwt);
return decodedJwt;
} catch (err) {
console.log(err.name);
console.log(err.message);
return err;
}
}
module.exports = {
addToCart,
getCartItems,
removeCartItem
}

JsonWebTokenError 해결하기
올바르지 않은 토큰이 들어왔을 때의 오류
else if(authorization instanceof jwt.JsonWebTokenError) {
return res.status(StatusCodes.BAD_REQUEST).json({
"message" : "잘못된 토큰입니다."
});
}'Devcourse > BookShop 사이드 프로젝트' 카테고리의 다른 글
| [BookShop- FE] React 스타일링 셋업 & 테마 시스템 (0) | 2026.04.14 |
|---|---|
| [BookShop 프로젝트] 백엔드 마무리하기 (0) | 2026.03.18 |
| [BookShop 프로젝트] 주문 API - LAST_INSERT_ID(), MAX()로 최신 데이터 가져오기, insertId, 벌크 INSERT (0) | 2026.02.20 |
| [BookShop 프로젝트] 장바구니 API - fk제약조건, in(~, ~) (0) | 2026.02.19 |
| [BookShop] 좋아요 API 구현 - count(), EXISTS (0) | 2026.02.18 |