Notice
Recent Posts
Link
정화 코딩
[Node.js] jwt 토큰으로 회원가입/로그인/로그아웃 구현 본문
관련 패키지 (jsonwebtoken, cookie-parser) 설치
npm install jsonwebtoken
npm install cookie-parser --save
jwt.js
import jwt from 'jsonwebtoken';
const secretKey = process.env.JWT_SECRET_KEY;
// 새로운 토큰을 생성하는 함수
export const generateToken = (payload) => {
const token = jwt.sign(payload, secretKey, { expiresIn: '10m' });
return token;
};
// 기존 토큰을 사용하여 새로운 토큰을 생성하는 함수
export const refreshToken = (token) => {
try {
const decoded = jwt.verify(token, secretKey);
const payload = {
userId: decoded.userId,
isAdmin: decoded.isAdmin,
};
const newToken = generateToken(payload);
return newToken;
} catch (error) {
console.error('Error refreshing token:', error);
return null;
}
};
// 로그인이 필요한 api 요청 시
export function loginRequired(req, res, next) {
// 헤더에서 토큰 가져오기
const headerToken = req.headers['authorization']?.split(' ')[1];
// 쿠키에서 토큰 가져오기
const cookieToken = req.cookies.token;
const token = headerToken || cookieToken;
// 토큰이 없을 경우
if (!token || token === "null") {
console.log("Authorization 토큰: 없음");
res.status(401).json({
result: "forbidden-approach",
message: "로그인한 유저만 사용할 수 있는 서비스입니다.",
});
return;
}
// 해당 토큰이 정상적인 토큰인지 확인
try {
const jwtDecoded = jwt.verify(token, secretKey);
const userId = jwtDecoded.userId;
req.currentUserId = userId;
// 토큰 갱신
const newToken = refreshToken(token);
if (newToken) {
res.cookie('token', newToken, { httpOnly: true, maxAge: 3600000 });
}
next();
} catch (error) {
res.status(401).json({
result: "forbidden-approach",
message: "정상적인 토큰이 아닙니다.",
});
return;
}
}
app.js
import * as dotenv from 'dotenv';
dotenv.config();
import express from 'express';
import bcrypt from "bcryptjs";
import cookieParser from "cookie-parser";
import { PrismaClient, Prisma } from '@prisma/client';
import jwt from 'jsonwebtoken';
import { generateToken, loginRequired } from './jwt.js';
//import jwtt from './jwt.js';
const prisma = new PrismaClient();
const secretKey = process.env.JWT_SECRET_KEY;
const app = express();
app.use(express.json());
app.use(cookieParser());
// 회원가입
app.post("/register", asyncHandler(async (req, res) => {
const { id, password } = req.body;
const user = await prisma.user.findUnique({
where: { id },
});
if (user) {
return res.status(400).json({ message: "이미 존재하는 아이디입니다." });
}
const hashedPassword = bcrypt.hashSync(password, 10);
const newUser = await prisma.user.create({
data: {
id: id,
password: hashedPassword,
},
});
res.status(201).send(newUser);
}));
// 로그인
app.post("/login", asyncHandler(async (req, res) => {
const { id, password } = req.body;
const user = await prisma.user.findUnique({
where: { id },
});
// 해당 유저가 없는 경우
if (!user) {
console.log("가입되지 않은 아이디입니다.");
return res.status(400).json({ message: "가입되지 않은 아이디입니다." });
}
// 비밀번호가 일치하는지 확인
const isMatch = bcrypt.compareSync(password, user.password);
if (isMatch) {
const payload = { userId: id };
const token = generateToken(payload);
res.cookie('token', token, { httpOnly: true, maxAge: 3600000 });
res.json({ message: "로그인 되었습니다." });
} else {
res.status(400).json({ message: "비밀번호가 일치하지 않습니다." });
}
}));
// 로그아웃
app.post("/logout", asyncHandler(async (req, res) => {
const token = req.cookies.token;
// 토큰이 없을 경우
if (!token) {
res.status(400).json({ message: '토큰이 없습니다. 로그인 상태를 확안하세요.' });
return;
}
// 토큰이 정상적인 토큰이 아닌 경우
const decoded = jwt.decode(token);
if (!decoded) {
res.status(401).json({ message: '잘못된 토큰입니다. 로그인 상태를 확인하세요.' });
return;
}
// 쿠키 삭제
res.clearCookie('token');
res.json({ message: '로그아웃 되었습니다.' });
}));
'Web Development' 카테고리의 다른 글
[Back-end] AWS EC2 인스턴스를 이용한 백엔드 배포 (0) | 2024.09.07 |
---|---|
[Node.js] Google OAuth 2.0으로 로그인/로그아웃 구현 (0) | 2024.08.02 |
[Back-end] codeit : 프로그래밍과 데이터 in JavaScript (0) | 2024.05.21 |
[Back-end] codeit : 프로그래밍 핵심 개념 in JavaScript (0) | 2024.05.21 |
[Back-end] codeit : 프로그래밍 시작하기 in JavaScript (0) | 2024.05.19 |
Comments