Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const userModel = require('../models/userModel'); const { getDb } = require('../dbPool'); // 로그인 이력 기록 (서비스 내부 헬퍼 함수) const recordLoginHistory = async (userId, success, ipAddress, userAgent, failureReason = null) => { try { const db = await getDb(); await db.execute( `INSERT INTO login_logs (user_id, login_time, ip_address, user_agent, login_status, failure_reason) VALUES (?, NOW(), ?, ?, ?, ?)`, [userId, ipAddress || 'unknown', userAgent || 'unknown', success ? 'success' : 'failed', failureReason] ); } catch (error) { console.error('로그인 이력 기록 실패:', error); } }; const loginService = async (username, password, ipAddress, userAgent) => { // 서비스 레이어에서는 더 이상 DB 커넥션을 직접 다루지 않음 try { const user = await userModel.findByUsername(username); if (!user) { console.log(`[로그인 실패] 사용자를 찾을 수 없음: ${username}`); return { success: false, status: 401, error: '아이디 또는 비밀번호가 올바르지 않습니다.' }; } if (user.is_active === false) { await recordLoginHistory(user.user_id, false, ipAddress, userAgent, 'account_disabled'); return { success: false, status: 403, error: '비활성화된 계정입니다. 관리자에게 문의하세요.' }; } if (user.locked_until && new Date(user.locked_until) > new Date()) { const remainingTime = Math.ceil((new Date(user.locked_until) - new Date()) / 1000 / 60); return { success: false, status: 429, error: `계정이 잠겨있습니다. ${remainingTime}분 후에 다시 시도하세요.` }; } const isValid = await bcrypt.compare(password, user.password); if (!isValid) { console.log(`[로그인 실패] 비밀번호 불일치: ${username}`); // 모델 함수를 사용하여 로그인 실패 처리 await userModel.incrementFailedLoginAttempts(user.user_id); if (user.failed_login_attempts >= 4) { await userModel.lockUserAccount(user.user_id); } await recordLoginHistory(user.user_id, false, ipAddress, userAgent, 'invalid_password'); return { success: false, status: 401, error: '아이디 또는 비밀번호가 올바르지 않습니다.' }; } // 성공 시 모델 함수를 사용하여 상태 초기화 await userModel.resetLoginAttempts(user.user_id); const token = jwt.sign( { user_id: user.user_id, username: user.username, role: user.role, access_level: user.access_level, worker_id: user.worker_id, name: user.name || user.username }, process.env.JWT_SECRET || 'your-secret-key', { expiresIn: process.env.JWT_EXPIRES_IN || '24h' } ); const refreshToken = jwt.sign( { user_id: user.user_id, type: 'refresh' }, process.env.JWT_REFRESH_SECRET || process.env.JWT_SECRET || 'your-refresh-secret', { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d' } ); await recordLoginHistory(user.user_id, true, ipAddress, userAgent); console.log(`[로그인 성공] 사용자: ${user.username} (${user.access_level})`); return { success: true, data: { token, refreshToken, user: { user_id: user.user_id, username: user.username, name: user.name || user.username, role: user.role, access_level: user.access_level, worker_id: user.worker_id } } }; } catch (error) { console.error('Login service error:', error); throw new Error('서버 오류가 발생했습니다.'); } // 서비스 레이어에서는 더 이상 DB 커넥션을 직접 다루지 않음 }; module.exports = { loginService, }; |