diff --git a/SPMS.API/Controllers/AuthController.cs b/SPMS.API/Controllers/AuthController.cs index d90bb27..d148255 100644 --- a/SPMS.API/Controllers/AuthController.cs +++ b/SPMS.API/Controllers/AuthController.cs @@ -63,4 +63,24 @@ public class AuthController : ControllerBase await _authService.LogoutAsync(adminId); return Ok(ApiResponse.Success()); } + + [HttpPost("password/change")] + [Authorize] + [SwaggerOperation( + Summary = "비밀번호 변경", + Description = "현재 로그인된 관리자의 비밀번호를 변경합니다.")] + [SwaggerResponse(200, "비밀번호 변경 성공")] + [SwaggerResponse(400, "현재 비밀번호 불일치")] + [SwaggerResponse(401, "인증되지 않은 요청")] + public async Task ChangePasswordAsync([FromBody] ChangePasswordRequestDto request) + { + var adminIdClaim = User.FindFirst("adminId")?.Value; + if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId)) + { + return Unauthorized(ApiResponse.Fail("101", "인증 정보가 유효하지 않습니다.")); + } + + await _authService.ChangePasswordAsync(adminId, request); + return Ok(ApiResponse.Success()); + } } diff --git a/SPMS.Application/DTOs/Auth/ChangePasswordRequestDto.cs b/SPMS.Application/DTOs/Auth/ChangePasswordRequestDto.cs new file mode 100644 index 0000000..0707e04 --- /dev/null +++ b/SPMS.Application/DTOs/Auth/ChangePasswordRequestDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace SPMS.Application.DTOs.Auth; + +public class ChangePasswordRequestDto +{ + [Required(ErrorMessage = "현재 비밀번호를 입력해주세요.")] + public string CurrentPassword { get; set; } = string.Empty; + + [Required(ErrorMessage = "새 비밀번호를 입력해주세요.")] + [MinLength(8, ErrorMessage = "비밀번호는 8자 이상이어야 합니다.")] + public string NewPassword { get; set; } = string.Empty; +} diff --git a/SPMS.Application/Interfaces/IAuthService.cs b/SPMS.Application/Interfaces/IAuthService.cs index 880120f..111592f 100644 --- a/SPMS.Application/Interfaces/IAuthService.cs +++ b/SPMS.Application/Interfaces/IAuthService.cs @@ -7,4 +7,5 @@ public interface IAuthService Task LoginAsync(LoginRequestDto request); Task RefreshTokenAsync(TokenRefreshRequestDto request); Task LogoutAsync(long adminId); + Task ChangePasswordAsync(long adminId, ChangePasswordRequestDto request); } diff --git a/SPMS.Application/Services/AuthService.cs b/SPMS.Application/Services/AuthService.cs index 0337e21..b8761be 100644 --- a/SPMS.Application/Services/AuthService.cs +++ b/SPMS.Application/Services/AuthService.cs @@ -146,4 +146,31 @@ public class AuthService : IAuthService _adminRepository.Update(admin); await _unitOfWork.SaveChangesAsync(); } + + public async Task ChangePasswordAsync(long adminId, ChangePasswordRequestDto request) + { + // 1. 관리자 조회 + var admin = await _adminRepository.GetByIdAsync(adminId); + if (admin is null) + { + throw new SpmsException( + ErrorCodes.NotFound, + "관리자를 찾을 수 없습니다.", + 404); + } + + // 2. 현재 비밀번호 검증 + if (!BCrypt.Net.BCrypt.Verify(request.CurrentPassword, admin.Password)) + { + throw new SpmsException( + ErrorCodes.PasswordValidationFailed, + "현재 비밀번호가 일치하지 않습니다.", + 400); + } + + // 3. 새 비밀번호 해싱 및 저장 + admin.Password = BCrypt.Net.BCrypt.HashPassword(request.NewPassword); + _adminRepository.Update(admin); + await _unitOfWork.SaveChangesAsync(); + } }