SPMS_API/SPMS.API/Controllers/PasswordController.cs
SEAN 3acae06ed1 improvement: 임시 비밀번호 발급 및 강제변경 플로우 구현 (#207)
- Admin 엔티티에 MustChangePassword, TempPasswordIssuedAt 필드 추가
- POST /v1/in/account/password/temp 엔드포인트 추가
- 임시비밀번호 생성(12자, 영대소+숫자+특수) 및 메일 발송
- 로그인 시 CHANGE_PASSWORD 분기 추가 (VERIFY_EMAIL > CHANGE_PASSWORD > GO_DASHBOARD)
- 비밀번호 변경 시 MustChangePassword 플래그 자동 해제
- LoginResponseDto에 must_change_password 필드 추가
- EF Core 마이그레이션 생성 및 적용

Closes #207
2026-02-25 10:51:37 +09:00

59 lines
2.3 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using SPMS.Application.DTOs.Account;
using SPMS.Application.Interfaces;
using SPMS.Domain.Common;
namespace SPMS.API.Controllers;
[ApiController]
[Route("v1/in/account/password")]
[ApiExplorerSettings(GroupName = "account")]
[AllowAnonymous]
public class PasswordController : ControllerBase
{
private readonly IAuthService _authService;
public PasswordController(IAuthService authService)
{
_authService = authService;
}
[HttpPost("forgot")]
[SwaggerOperation(
Summary = "비밀번호 찾기",
Description = "등록된 이메일로 비밀번호 재설정 토큰을 발송합니다. 보안을 위해 이메일 존재 여부와 관계없이 동일한 응답을 반환합니다.")]
[SwaggerResponse(200, "재설정 메일 발송 완료")]
[SwaggerResponse(400, "잘못된 요청")]
public async Task<IActionResult> ForgotPasswordAsync([FromBody] PasswordForgotRequestDto request)
{
await _authService.ForgotPasswordAsync(request);
return Ok(ApiResponse.Success());
}
[HttpPost("reset")]
[SwaggerOperation(
Summary = "비밀번호 재설정",
Description = "이메일로 받은 재설정 토큰과 새 비밀번호로 비밀번호를 재설정합니다.")]
[SwaggerResponse(200, "비밀번호 재설정 성공")]
[SwaggerResponse(400, "토큰 불일치 또는 만료")]
public async Task<IActionResult> ResetPasswordAsync([FromBody] PasswordResetRequestDto request)
{
await _authService.ResetPasswordAsync(request);
return Ok(ApiResponse.Success());
}
[HttpPost("temp")]
[SwaggerOperation(
Summary = "임시 비밀번호 발급",
Description = "등록된 이메일로 임시 비밀번호를 발송합니다. 보안을 위해 이메일 존재 여부와 관계없이 동일한 응답을 반환합니다.")]
[SwaggerResponse(200, "임시 비밀번호 발송 완료")]
[SwaggerResponse(400, "잘못된 요청")]
public async Task<IActionResult> IssueTempPasswordAsync([FromBody] TempPasswordRequestDto request)
{
await _authService.IssueTempPasswordAsync(request);
return Ok(ApiResponse.Success());
}
}