블랙리스트를 사용하는 이유는 다음과 같다:
토큰 무효화: 로그아웃 후에도 사용자의 토큰이 유효한 동안에는 그 토큰을 사용하여 요청을 보낼 수 있다. 블랙리스트를 사용하면 로그아웃된 토큰을 추가하여 해당 토큰을 무효화시킬 수 있다. 따라서 블랙리스트를 통해 로그아웃한 토큰을 체크하여 무효화할 수 있다.
보안 강화: 토큰이 유출되었을 때, 클라이언트에서 로그아웃을 했다고 해도 해당 토큰은 여전히 유효하다. 블랙리스트를 사용하면 유출된 토큰을 무효화하여 보안을 강화할 수 있다.
로그아웃 이후의 처리: 로그아웃은 서버와 클라이언트 간의 세션을 끊는 것이지만, 토큰은 여전히 유효할 수 있다. 블랙리스트를 사용하면 로그아웃 시 토큰을 무효화하고, 클라이언트에서 다시 해당 토큰을 사용하는 시도를 차단할 수 있다.
블랙리스트를 사용함으로써, 토큰의 안전성과 보안성을 높일 수 있다.
예제:
토큰을 검증하고 사용자를 찾아 req.user에 할당하는 authenticate 미들웨어.
// authenticate 미들웨어
const jwt = require("jsonwebtoken");
const { models } = require('../models');
const userModel = models.User;
async function authMiddleware(req, res, next) {
const token = req.headers.authorization && req.headers.authorization.split(" ")[1];
if (!token) {
return res.status(401).json({ error: "Unauthorized - No token provided" });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await userModel.findByPk(decoded.userId);
if (!user) {
return res.status(401).json({ error: "Unauthorized - User not found" });
}
req.user = user.toJSON(); // req.user에 사용자 정보를 할당
next();
} catch (error) {
return res.status(401).json({ error: "Unauthorized - Invalid token" });
}
}
module.exports = authMiddleware;
로그아웃 및 토큰 블랙리스트
const blacklist = require('../blacklist'); // 로그아웃 토큰 블랙리스트
// 로그아웃
router.post('/logout', authenticate, (req, res) => {
try {
const token = req.headers.authorization.split(' ')[1];
// 토큰 검증
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).json({ error: '토큰 검증에 실패했습니다.' });
}
// 만료 시간 확인
if (decoded.exp <= Date.now() / 1000) {
return res.status(401).json({ error: '만료된 토큰입니다.' });
}
// 블랙리스트에 토큰 추가
blacklist.push(token);
res.status(200).json({ message: '로그아웃에 성공했습니다.' });
});
} catch (error) {
console.error(error);
res.status(500).json({ error: '서버에러가 발생했습니다.' });
}
});
로그아웃 API에서 authenticate 미들웨어를 사용하여 인증을 확인하고, 유효한 토큰일 경우 블랙리스트에 추가한다. 향후 확장성을 고려하여 블랙리스트를 데이터베이스에 저장하는 방식으로 개선할 수 있다. 현재는 블랙리스트를 메모리에 저장하고 있다.