using Microsoft.Extensions.Options; using SPMS.Application.DTOs.Auth; using SPMS.Application.Interfaces; using SPMS.Application.Settings; using SPMS.Domain.Common; using SPMS.Domain.Exceptions; using SPMS.Domain.Interfaces; namespace SPMS.Application.Services; public class AuthService : IAuthService { private readonly IAdminRepository _adminRepository; private readonly IUnitOfWork _unitOfWork; private readonly IJwtService _jwtService; private readonly JwtSettings _jwtSettings; public AuthService( IAdminRepository adminRepository, IUnitOfWork unitOfWork, IJwtService jwtService, IOptions jwtSettings) { _adminRepository = adminRepository; _unitOfWork = unitOfWork; _jwtService = jwtService; _jwtSettings = jwtSettings.Value; } public async Task LoginAsync(LoginRequestDto request) { // 1. 이메일로 관리자 조회 var admin = await _adminRepository.GetByEmailAsync(request.Email); if (admin is null) { throw new SpmsException( ErrorCodes.LoginFailed, "이메일 또는 비밀번호가 일치하지 않습니다.", 401); } // 2. 삭제된 계정 확인 if (admin.IsDeleted) { throw new SpmsException( ErrorCodes.LoginFailed, "이메일 또는 비밀번호가 일치하지 않습니다.", 401); } // 3. 비밀번호 검증 (BCrypt) if (!BCrypt.Net.BCrypt.Verify(request.Password, admin.Password)) { throw new SpmsException( ErrorCodes.LoginFailed, "이메일 또는 비밀번호가 일치하지 않습니다.", 401); } // 4. 토큰 생성 var accessToken = _jwtService.GenerateAccessToken( admin.Id, admin.Role.ToString()); var refreshToken = _jwtService.GenerateRefreshToken(); // 5. 최종 로그인 시간 업데이트 admin.LastLoginAt = DateTime.UtcNow; _adminRepository.Update(admin); await _unitOfWork.SaveChangesAsync(); // 6. 응답 반환 return new LoginResponseDto { AccessToken = accessToken, RefreshToken = refreshToken, ExpiresIn = _jwtSettings.ExpiryMinutes * 60, Admin = new AdminInfoDto { AdminCode = admin.AdminCode, Email = admin.Email, Name = admin.Name, Role = admin.Role.ToString() } }; } }