// 인증 컨트롤러 // 기존 Java ApiLoginController를 Node.js로 포팅 import { Request, Response } from "express"; import { AuthService } from "../services/authService"; import { JwtUtils } from "../utils/jwtUtils"; import { LoginRequest, UserInfo, ApiResponse, PersonBean } from "../types/auth"; import { logger } from "../utils/logger"; export class AuthController { /** * POST /api/auth/login * 기존 Java ApiLoginController.login() 메서드 포팅 */ static async login(req: Request, res: Response): Promise { try { const { userId, password }: LoginRequest = req.body; const remoteAddr = req.ip || req.connection.remoteAddress || "unknown"; logger.info(`=== API 로그인 호출됨 ===`); logger.info(`userId: ${userId}`); logger.info(`password: ${password ? "***" : "null"}`); // 입력값 검증 if (!userId || !password) { res.status(400).json({ success: false, message: "사용자 ID와 비밀번호를 입력해주세요.", error: { code: "INVALID_INPUT", details: "필수 입력값이 누락되었습니다.", }, }); return; } // 로그인 프로세스 실행 const loginResult = await AuthService.processLogin( userId, password, remoteAddr ); if (loginResult.success && loginResult.userInfo && loginResult.token) { // 로그인 성공 const userInfo: UserInfo = { userId: loginResult.userInfo.userId, userName: loginResult.userInfo.userName || "", deptName: loginResult.userInfo.deptName || "", companyCode: loginResult.userInfo.companyCode || "ILSHIN", }; logger.info(`=== API 로그인 사용자 정보 디버그 ===`); logger.info( `PersonBean companyCode: ${loginResult.userInfo.companyCode}` ); logger.info(`반환할 사용자 정보:`); logger.info(`- userId: ${userInfo.userId}`); logger.info(`- userName: ${userInfo.userName}`); logger.info(`- companyCode: ${userInfo.companyCode}`); res.status(200).json({ success: true, message: "로그인 성공", data: { userInfo, token: loginResult.token, }, }); } else { // 로그인 실패 res.status(401).json({ success: false, message: "로그인 실패", error: { code: "LOGIN_FAILED", details: loginResult.errorReason || "알 수 없는 오류가 발생했습니다.", }, }); } } catch (error) { logger.error( `로그인 API 오류: ${error instanceof Error ? error.message : error}` ); res.status(500).json({ success: false, message: "서버 오류가 발생했습니다.", error: { code: "SERVER_ERROR", details: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.", }, }); } } /** * POST /api/auth/logout * 기존 Java ApiLoginController.logout() 메서드 포팅 */ static async logout(req: Request, res: Response): Promise { try { const remoteAddr = req.ip || req.connection.remoteAddress || "unknown"; // JWT 토큰에서 사용자 정보 추출 const authHeader = req.get("Authorization"); const token = authHeader && authHeader.split(" ")[1]; if (token) { try { const userInfo = JwtUtils.verifyToken(token); await AuthService.processLogout(userInfo.userId, remoteAddr); } catch (tokenError) { logger.warn( `로그아웃 시 토큰 검증 실패: ${tokenError instanceof Error ? tokenError.message : tokenError}` ); } } res.status(200).json({ success: true, message: "로그아웃되었습니다.", data: null, }); } catch (error) { logger.error( `로그아웃 API 오류: ${error instanceof Error ? error.message : error}` ); res.status(500).json({ success: false, message: "로그아웃 처리 중 오류가 발생했습니다.", error: { code: "LOGOUT_ERROR", details: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.", }, }); } } /** * GET /api/auth/me * 기존 Java ApiLoginController.getCurrentUser() 메서드 포팅 */ static async getCurrentUser(req: Request, res: Response): Promise { try { const authHeader = req.get("Authorization"); const token = authHeader && authHeader.split(" ")[1]; if (!token) { res.status(401).json({ success: false, message: "인증되지 않은 사용자입니다.", error: { code: "NOT_AUTHENTICATED", details: "세션이 만료되었거나 로그인이 필요합니다.", }, }); return; } const userInfo = JwtUtils.verifyToken(token); const userInfoResponse: UserInfo = { userId: userInfo.userId, userName: userInfo.userName || "", deptName: userInfo.deptName || "", companyCode: userInfo.companyCode || "ILSHIN", userType: userInfo.userType || "USER", userTypeName: userInfo.userTypeName || "일반사용자", isAdmin: userInfo.userType === "ADMIN" || userInfo.userId === "plm_admin", }; res.status(200).json({ success: true, message: "사용자 정보 조회 성공", data: userInfoResponse, }); } catch (error) { logger.error( `사용자 정보 조회 API 오류: ${error instanceof Error ? error.message : error}` ); res.status(401).json({ success: false, message: "인증되지 않은 사용자입니다.", error: { code: "NOT_AUTHENTICATED", details: "세션이 만료되었거나 로그인이 필요합니다.", }, }); } } /** * GET /api/auth/status * 기존 Java ApiLoginController.checkAuthStatus() 메서드 포팅 */ static async checkAuthStatus(req: Request, res: Response): Promise { try { const authHeader = req.get("Authorization"); const token = authHeader && authHeader.split(" ")[1]; if (!token) { res.status(200).json({ success: true, message: "세션 상태 확인", data: { isLoggedIn: false, isAdmin: false, }, }); return; } const validation = JwtUtils.validateToken(token); res.status(200).json({ success: true, message: "세션 상태 확인", data: { isLoggedIn: validation.isValid, isAdmin: false, // TODO: 실제 관리자 권한 확인 로직 추가 error: validation.error, }, }); } catch (error) { logger.error( `세션 상태 확인 API 오류: ${error instanceof Error ? error.message : error}` ); res.status(500).json({ success: false, message: "세션 상태 확인 중 오류가 발생했습니다.", error: { code: "SESSION_CHECK_ERROR", details: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.", }, }); } } /** * POST /api/auth/refresh * JWT 토큰 갱신 API */ static async refreshToken(req: Request, res: Response): Promise { try { const authHeader = req.get("Authorization"); const token = authHeader && authHeader.split(" ")[1]; if (!token) { res.status(401).json({ success: false, message: "토큰이 필요합니다.", error: { code: "TOKEN_MISSING", details: "인증 토큰이 필요합니다.", }, }); return; } const newToken = JwtUtils.refreshToken(token); res.status(200).json({ success: true, message: "토큰 갱신 성공", data: { token: newToken, }, }); } catch (error) { logger.error( `토큰 갱신 API 오류: ${error instanceof Error ? error.message : error}` ); res.status(401).json({ success: false, message: "토큰 갱신에 실패했습니다.", error: { code: "TOKEN_REFRESH_ERROR", details: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.", }, }); } } }