- ChangePasswordRequestDto 추가 - IAuthService/AuthService에 ChangePasswordAsync 구현 - AuthController에 POST /v1/in/auth/password/change 엔드포인트 추가 - 현재 비밀번호 검증 및 BCrypt 해싱 적용 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
87 lines
3.3 KiB
C#
87 lines
3.3 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Swashbuckle.AspNetCore.Annotations;
|
|
using SPMS.Application.DTOs.Auth;
|
|
using SPMS.Application.Interfaces;
|
|
using SPMS.Domain.Common;
|
|
|
|
namespace SPMS.API.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("v1/in/auth")]
|
|
[ApiExplorerSettings(GroupName = "auth")]
|
|
public class AuthController : ControllerBase
|
|
{
|
|
private readonly IAuthService _authService;
|
|
|
|
public AuthController(IAuthService authService)
|
|
{
|
|
_authService = authService;
|
|
}
|
|
|
|
[HttpPost("login")]
|
|
[AllowAnonymous]
|
|
[SwaggerOperation(
|
|
Summary = "관리자 로그인",
|
|
Description = "이메일과 비밀번호로 로그인하여 JWT 토큰을 발급받습니다.")]
|
|
[SwaggerResponse(200, "로그인 성공", typeof(ApiResponse<LoginResponseDto>))]
|
|
[SwaggerResponse(401, "로그인 실패")]
|
|
public async Task<IActionResult> LoginAsync([FromBody] LoginRequestDto request)
|
|
{
|
|
var result = await _authService.LoginAsync(request);
|
|
return Ok(ApiResponse<LoginResponseDto>.Success(result));
|
|
}
|
|
|
|
[HttpPost("token/refresh")]
|
|
[AllowAnonymous]
|
|
[SwaggerOperation(
|
|
Summary = "토큰 갱신",
|
|
Description = "Refresh Token을 사용하여 새로운 Access Token과 Refresh Token을 발급받습니다.")]
|
|
[SwaggerResponse(200, "토큰 갱신 성공", typeof(ApiResponse<TokenRefreshResponseDto>))]
|
|
[SwaggerResponse(401, "유효하지 않거나 만료된 Refresh Token")]
|
|
public async Task<IActionResult> RefreshTokenAsync([FromBody] TokenRefreshRequestDto request)
|
|
{
|
|
var result = await _authService.RefreshTokenAsync(request);
|
|
return Ok(ApiResponse<TokenRefreshResponseDto>.Success(result));
|
|
}
|
|
|
|
[HttpPost("logout")]
|
|
[Authorize]
|
|
[SwaggerOperation(
|
|
Summary = "로그아웃",
|
|
Description = "현재 로그인된 관리자의 Refresh Token을 무효화합니다.")]
|
|
[SwaggerResponse(200, "로그아웃 성공")]
|
|
[SwaggerResponse(401, "인증되지 않은 요청")]
|
|
public async Task<IActionResult> LogoutAsync()
|
|
{
|
|
var adminIdClaim = User.FindFirst("adminId")?.Value;
|
|
if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId))
|
|
{
|
|
return Unauthorized(ApiResponse<object>.Fail("101", "인증 정보가 유효하지 않습니다."));
|
|
}
|
|
|
|
await _authService.LogoutAsync(adminId);
|
|
return Ok(ApiResponse.Success());
|
|
}
|
|
|
|
[HttpPost("password/change")]
|
|
[Authorize]
|
|
[SwaggerOperation(
|
|
Summary = "비밀번호 변경",
|
|
Description = "현재 로그인된 관리자의 비밀번호를 변경합니다.")]
|
|
[SwaggerResponse(200, "비밀번호 변경 성공")]
|
|
[SwaggerResponse(400, "현재 비밀번호 불일치")]
|
|
[SwaggerResponse(401, "인증되지 않은 요청")]
|
|
public async Task<IActionResult> ChangePasswordAsync([FromBody] ChangePasswordRequestDto request)
|
|
{
|
|
var adminIdClaim = User.FindFirst("adminId")?.Value;
|
|
if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId))
|
|
{
|
|
return Unauthorized(ApiResponse<object>.Fail("101", "인증 정보가 유효하지 않습니다."));
|
|
}
|
|
|
|
await _authService.ChangePasswordAsync(adminId, request);
|
|
return Ok(ApiResponse.Success());
|
|
}
|
|
}
|