// app.js
import express from 'express';
import expressSession from 'express-session';
const app = express();
const PORT = 3019;
app.use(express.json());
app.use(
expressSession({
secret: 'express-session-secret-key.', // 세션을 암호화하는 비밀 키를 설정
resave: false, // 클라이언트의 요청이 올 때마다 세션을 새롭게 저장할 지 설정, 변경사항이 없어도 다시 저장
saveUninitialized: false, // 세션이 초기화되지 않았을 때 세션을 저장할 지 설정
cookie: {
// 세션 쿠키 설정
maxAge: 1000 * 60 * 60 * 24, // 쿠키의 만료 기간을 1일로 설정합니다.
},
}),
);
app.post("/sessions", (req, res, next) => {
const { userId } = req.body;
req.session.userId = userId;
return res.status(201).json({ message: "세션을 설정했습니다." });
});
app.get("/sessions", (req, res, next) => {
return res.status(200).json({
message: "세션을 조회했습니다",
sessions: req.session.userId ?? null,
});
});
app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});
한 유저당 한번만 작동된다.
서버를 껐다가 키면 session이 날라간다.
그래서 db에 session에 저장을 하며 된다.
이전에는 사용자가 로그인 성공 시, JWT를 생성하고 이를 쿠키로 전달하였습니다.
하지만, 저희는 이제 JWT 대신 express-session의 세션 ID를 사용해보려고 합니다. 로그인이 성공하면 세션 ID를 생성하고, 이를 쿠키로 사용자에게 전달할 예정입니다.
yarn add express-mysql-session
express-session을 MySQL에 저장할 수 있도록 해준다.
미들웨어
// import jwt from "jsonwebtoken";
import { prisma } from "../src/utils/prisma/index.js";
// jwt를 사용하지 않고 express-session을 사용
export default async function (req, res, next) {
try {
// const { authorization } = req.cookies;
// const [tokenType, token] = authorization.split(" ");
// if (tokenType !== "Bearer")
// throw new Error("토큰 타입이 일치하지 않습니다.");
// // 서버에서 발급한 jwt가 맞는지 검증한다.
// const decodedToken = jwt.verify(token, "key");
// const userId = decodedToken.userId;
const { userId } = req.session;
if (!userId) throw new Error("로그인이 필요합니다.");
const user = await prisma.users.findFirst({
where: { userId: +userId },
});
if (!user) {
// res.clearCookie("authorization");
throw new Error("토큰 사용자가 존재하지 않습니다."); // catch로 넘긴다.
}
// req.user에 user정보를 넣어준다
req.user = user;
next();
} catch (error) {
res.clearCookie("authorization");
// 에러 구분
switch (error.name) {
// case "TokenExpriredError": // 토큰이 만료되었을 때 발생하는 에러
// return res.status(401).json({ message: "토큰이 만료되었습니다." });
// break;
// case "JsonwebtokenEroor": // 토큰에 검증이 실패했을 때 발생하는 에러
// return res.status(401).json({ message: "토큰이 검증이 실패했습니다." });
// break;
default:
return res
.status(401)
.json({ message: error.name ?? "비정상적인 요청입니다." });
}
}
}
// // src/middlewares/auth.middleware.js
// import jwt from 'jsonwebtoken';
// import { prisma } from '../utils/prisma/index.js';
// export default async function (req, res, next) {
// try {
// const { authorization } = req.cookies;
// if (!authorization) throw new Error('토큰이 존재하지 않습니다.');
// const [tokenType, token] = authorization.split(' ');
// if (tokenType !== 'Bearer')
// throw new Error('토큰 타입이 일치하지 않습니다.');
// const decodedToken = jwt.verify(token, 'customized_secret_key');
// const userId = decodedToken.userId;
// const user = await prisma.users.findFirst({
// where: { userId: +userId },
// });
// if (!user) {
// res.clearCookie('authorization');
// throw new Error('토큰 사용자가 존재하지 않습니다.');
// }
// // req.user에 사용자 정보를 저장합니다.
// req.user = user;
// next();
// } catch (error) {
// res.clearCookie('authorization');
// // 토큰이 만료되었거나, 조작되었을 때, 에러 메시지를 다르게 출력합니다.
// switch (error.name) {
// case 'TokenExpiredError':
// return res.status(401).json({ message: '토큰이 만료되었습니다.' });
// case 'JsonWebTokenError':
// return res.status(401).json({ message: '토큰이 조작되었습니다.' });
// default:
// return res
// .status(401)
// .json({ message: error.message ?? '비정상적인 요청입니다.' });
// }
// }
// }
로그인 라우터
router.post("/sign-in", async (req, res, next) => {
const { email, password } = req.body;
const user = await prisma.Users.findFirst({
where: { email },
});
if (!user) {
return res.status(401).json({ message: "존재하지 않는 이메일입니다." });
// 401 없는
}
// const result = await bcrypt.compare(password, user.password)
if (!(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ message: "비밀번호가 일치하지 않습니다." });
}
req.session.userId = user.userId;
// 토큰
// const token = jwt.sign(
// {
// userId: user.userId,
// },
// "key" // 비밀 키는 env에 넣어야 돼
// );
// res.cookie("authorization", `Bearer ${token}`);
// Bearer 하고 %20 이 나오는데 이건 스페이스를 뜻한다.
return res.status(200).json({ message: "로그인이 완료 되었습니다." });
// 뭔가를 보낸 게 아니라 200
});