# All files / services auth.service.js

0% Statements 0/38
0% Branches 0/32
0% Functions 0/2
0% Lines 0/38

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,
    };