// src/controllers/auth.controller.js // 인증 컨트롤러 const jwt = require('jsonwebtoken'); const { User } = require('../models'); const logger = require('../config/logger.config'); const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'; const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d'; const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'your-refresh-secret'; const JWT_REFRESH_EXPIRES_IN = process.env.JWT_REFRESH_EXPIRES_IN || '30d'; /** * JWT 토큰 생성 */ function generateTokens(user) { const accessToken = jwt.sign( { userId: user.id, email: user.email, role: user.role }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ); const refreshToken = jwt.sign( { userId: user.id }, JWT_REFRESH_SECRET, { expiresIn: JWT_REFRESH_EXPIRES_IN } ); return { accessToken, refreshToken }; } /** * 회원가입 */ exports.register = async (req, res, next) => { try { const { email, password, name } = req.body; // 이메일 중복 확인 const existingUser = await User.findOne({ where: { email } }); if (existingUser) { return res.status(409).json({ success: false, error: { code: 'EMAIL_ALREADY_EXISTS', message: '이미 등록된 이메일입니다.', }, }); } // 사용자 생성 const user = await User.create({ email, password, name, }); // 토큰 생성 const tokens = generateTokens(user); logger.info(`새 사용자 가입: ${email}`); return res.status(201).json({ success: true, data: { user: user.toSafeJSON(), ...tokens, }, }); } catch (error) { return next(error); } }; /** * 로그인 */ exports.login = async (req, res, next) => { try { const { email, password } = req.body; // 사용자 조회 const user = await User.findOne({ where: { email } }); if (!user) { return res.status(401).json({ success: false, error: { code: 'INVALID_CREDENTIALS', message: '이메일 또는 비밀번호가 올바르지 않습니다.', }, }); } // 비밀번호 검증 const isValidPassword = await user.validatePassword(password); if (!isValidPassword) { return res.status(401).json({ success: false, error: { code: 'INVALID_CREDENTIALS', message: '이메일 또는 비밀번호가 올바르지 않습니다.', }, }); } // 계정 상태 확인 if (user.status !== 'active') { return res.status(403).json({ success: false, error: { code: 'ACCOUNT_INACTIVE', message: '계정이 비활성화되었습니다. 관리자에게 문의하세요.', }, }); } // 마지막 로그인 시간 업데이트 user.lastLoginAt = new Date(); await user.save(); // 토큰 생성 const tokens = generateTokens(user); logger.info(`사용자 로그인: ${email}`); return res.json({ success: true, data: { user: user.toSafeJSON(), ...tokens, }, }); } catch (error) { return next(error); } }; /** * 토큰 갱신 */ exports.refresh = async (req, res, next) => { try { const { refreshToken } = req.body; // 리프레시 토큰 검증 let decoded; try { decoded = jwt.verify(refreshToken, JWT_REFRESH_SECRET); } catch (error) { return res.status(401).json({ success: false, error: { code: 'INVALID_REFRESH_TOKEN', message: '유효하지 않은 리프레시 토큰입니다.', }, }); } // 사용자 조회 const user = await User.findByPk(decoded.userId); if (!user || user.status !== 'active') { return res.status(401).json({ success: false, error: { code: 'USER_NOT_FOUND', message: '사용자를 찾을 수 없습니다.', }, }); } // 새 토큰 생성 const tokens = generateTokens(user); return res.json({ success: true, data: tokens, }); } catch (error) { return next(error); } }; /** * 로그아웃 */ exports.logout = async (req, res) => { // 클라이언트에서 토큰 삭제 처리 // 서버에서는 특별한 처리 없음 (필요시 블랙리스트 구현) return res.json({ success: true, data: { message: '로그아웃되었습니다.', }, }); };