본문 바로가기
IT & Tech 정보

🚀 REST API 인증·권한 관리: Node.js + Express + JWT

by 지식과 지혜의 나무 2025. 5. 25.
반응형


안녕하세요, 즐로그 운영자입니다!
오늘은 Node.js+Express 기반 REST API에서 **JWT(Json Web Token)**를 활용해
“인증(Authentication)‧권한 관리(Authorization)”를 구현하는 방법을 단계별로 소개합니다.
코드 스니펫을 그대로 복사해 붙여넣기만 하면 직접 테스트해볼 수 있어요~ 😉



📋 목차
1. 왜 JWT인가?
2. 프로젝트 세팅
3. JWT 발급‧검증 미들웨어 작성
4. 회원가입·로그인 라우트 구현
5. 보호된 라우트(권한 검사) 구현
6. 실전 팁 & 보안 고려사항
7. 마무리



1️⃣ 왜 JWT인가?
• 자체 토큰 기반: 서버에 세션 저장 없이도 클라이언트 검증 가능
• 확장성: 분산 시스템·마이크로서비스 간 인증 공유
• 표준 규격: 헤더(Header)·페이로드(Payload)·서명(Signature) 구조로 가독성·안정성 확보



2️⃣ 프로젝트 세팅

# 1) 새 프로젝트 생성
mkdir express-jwt-auth && cd express-jwt-auth
npm init -y

# 2) 필수 패키지 설치
npm install express jsonwebtoken bcryptjs dotenv

# 3) 개발 편의용
npm install --save-dev nodemon

// package.json (scripts 부분)
"scripts": {
  "start": "node index.js",
  "dev": "nodemon index.js"
}

# 4) .env 파일 생성
echo "JWT_SECRET=your_super_secret_key" >> .env
echo "PORT=4000" >> .env




3️⃣ JWT 발급·검증 미들웨어 작성

// auth.js
require('dotenv').config();
const jwt = require('jsonwebtoken');

// 토큰 발급 함수
function signToken(user) {
  // 페이로드에 최소 정보만 담기 (예: userId, role)
  const payload = { id: user.id, role: user.role };
  return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });
}

// 토큰 검증 미들웨어
function verifyToken(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader) return res.status(401).json({ error: '토큰 누락' });

  const token = authHeader.split(' ')[1];
  jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
    if (err) return res.status(403).json({ error: '유효하지 않은 토큰' });
    req.user = decoded; // req.user.id, req.user.role 사용 가능
    next();
  });
}

// 권한 검사 미들웨어 (예: admin 전용)
function requireRole(role) {
  return (req, res, next) => {
    if (req.user.role !== role) {
      return res.status(403).json({ error: '권한이 없습니다' });
    }
    next();
  };
}

module.exports = { signToken, verifyToken, requireRole };




4️⃣ 회원가입·로그인 라우트 구현

// index.js
require('dotenv').config();
const express = require('express');
const bcrypt = require('bcryptjs');
const { signToken, verifyToken, requireRole } = require('./auth');

const app = express();
app.use(express.json());

const users = []; // 예시용 메모리 DB

// 1. 회원가입
app.post('/signup', async (req, res) => {
  const { username, password, role } = req.body;
  const hashed = await bcrypt.hash(password, 10);
  const user = { id: users.length + 1, username, password: hashed, role: role || 'user' };
  users.push(user);
  res.json({ message: '회원가입 완료' });
});

// 2. 로그인
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);
  if (!user) return res.status(400).json({ error: '유저 없음' });

  const valid = await bcrypt.compare(password, user.password);
  if (!valid) return res.status(400).json({ error: '비밀번호 불일치' });

  const token = signToken(user);
  res.json({ token });
});

// 3. 공개 라우트
app.get('/public', (req, res) => {
  res.json({ message: '모두 접근 가능' });
});

// 4. 보호된 라우트 (인증 필요)
app.get('/protected', verifyToken, (req, res) => {
  res.json({ message: `안녕하세요, 유저 #${req.user.id}` });
});

// 5. 관리자 전용 라우트
app.get('/admin', verifyToken, requireRole('admin'), (req, res) => {
  res.json({ message: '관리자 전용 페이지' });
});

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`🚀 서버 실행 중: http://localhost:${PORT}`));




5️⃣ 실전 팁 & 보안 고려사항
• 비밀 키 관리: .env에 절대 노출 금지, Vault·Secret Manager 활용
• 토큰 만료: 짧은 수명(1h) + 리프레시 토큰 별도 구현
• HTTPS 적용: 전송 구간 암호화로 토큰 탈취 방지
• CORS 설정: 신뢰할 수 있는 도메인만 허용
• JWT 페이로드 최소화: 민감정보·장문 데이터 금지



6️⃣ 마무리

지금까지 Node.js+Express+JWT 기반 REST API에서
• 회원가입·로그인
• JWT 발급·검증
• 권한(Role) 검사

과정까지 포괄적으로 다뤄봤습니다.
코드 스니펫만 따라 해도 인증·권한 관리 기본 골격이 완성되니,
여러분 프로젝트에 바로 적용해 보세요!

다음 포스트에서 “비동기 작업 큐 처리(Python+Celery)” 편으로 이어갑니다~
행복한 개발 되세요! 👋

반응형